定义
模板模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
角色
- 抽象类(Abstract Class):实现了模板方法,定义了算法的骨架。
- 具体类(Concrete Class):实现抽象类中的抽象方法,以完成完整的算法。
类图

实现
| 12
 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
实际应用
需求:很多单据需要提供参照服务,其模式是固定的:接受参数 -> 解析参数 -> 查询 -> 类型转转 -> 返回,
除了查询方法不同之外,其他各步骤实现都可以是相同的。
实现:提供模板类,各单据继承该模板类。
代码:
| 12
 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函数,可以改进上面的实现:
| 12
 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函数,以避免类的增加。