定义
模板模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
角色
- 抽象类(Abstract Class):实现了模板方法,定义了算法的骨架。
- 具体类(Concrete Class):实现抽象类中的抽象方法,以完成完整的算法。
类图
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public abstract class AbstractClass {
final void templateMethod() { operation1(); operation2(); }
protected abstract void operation1();
protected abstract void operation2(); }
public class ConcreteClassA extends AbstractClass {
@Override protected void operation1() { System.out.println("operation1 of a");
}
@Override protected void operation2() { System.out.println("operation2 of a"); } }
public class ConcreteClassB extends AbstractClass {
@Override protected void operation1() { System.out.println("operation1 of b");
}
@Override protected void operation2() { System.out.println("operation2 of b"); } }
|
优缺点
优点
- 封装必变部分,扩展可变部分
- 提取公共代码,便于维护
- 行为由父类控制,子类实现
缺点
- 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大
适用场景
- 有多个子类共有的方法,且逻辑相同
- 重要的、复杂的方法,都可以考虑作为模板方法
模式应用
Spring Security
Java AQS抽象队列同步器
队列同步器(AbstractQueuedSynchronizer)是基于模板方法模式设计的,也就是说,使用者需要继承同步器并重写指定的方法,随后将同步器聚合在自定义的同步组件中,并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。
Java线程池
AbstractExecutorService
实际应用
需求:很多单据需要提供参照服务,其模式是固定的:接受参数 -> 解析参数 -> 查询 -> 类型转转 -> 返回,
除了查询方法不同之外,其他各步骤实现都可以是相同的。
实现:提供模板类,各单据继承该模板类。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public abstract class ReferService {
public final <T> ReferPageResponse<T> queryReferPage(Map<String, Object> params, T clazz) { Pageable pageable = buildPageable(params); Page<T> page = queryForPage(pageable, params, clazz); return buildResponse(page); }
protected abstract <T> Page<T> queryForPage(Pageable pageable, Map<String, Object> params, T clazz);
private Pageable buildPageable(Map<String, Object> params) { return null; }
private <T> ReferPageResponse<T> buildResponse(Page<T> page) { return null; } }
|
通过使用Java8 lambada函数,可以改进上面的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class ReferUtils {
public final <T> ReferPageResponse<T> queryReferPage(Map<String, Object> params, BiFunction<Pageable, Map, Page<T>> function) { Pageable pageable = buildPageable(params); Page<T> page = function.apply(pageable, params); return buildResponse(page); }
private Pageable buildPageable(Map<String, Object> params) { return null; }
private <T> ReferPageResponse<T> buildResponse(Page<T> page) { return null; } }
|
这样就不需要每个单据都创建子类了,而是改为传递数据查询函数。
简单业务中,如用到了行为型设计模式,基本都可以改为使用Java8 lambada函数,以避免类的增加。