
模板方法模式UML图
UML图

抽象类AbstractClass定义了算法框架templateMethod()方法,其中有2个方法primitve1()和primitve2()被抽象出来,子类SubClass1继承了抽象类AbstractClass,从而实现了primitve1()和primitve2()。
模板方法模式角色
抽象类(AbstractClass): 定义了算法核心框架,同时把局部的算法行为封装成步骤,让子类去实现。
子类(SubClass): 继承了抽象类,实现抽象类中的抽象方法,具体实现了算法部分逻辑。
模板方法模式源码示例
源码地址:Template-method
抽象方法
先定义抽象类,抽象类AbstractProcessor中核心算法handle方法中大体分3部,第一先校验参数具体怎么校验放在子类中实现,第二获取结果也放在子类实现,第三获取结果后的操作也放在子类实现。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
4j public abstract class <P extends Request, R extends Response> {
public R handle(P request) { log.info("开始处理, 请求参数={}", request); validRequest(request);
R response = getResponse(request); log.info("获取结果, 响应结果={}", response);
afterHandle(response); return response; }
protected abstract void afterHandle(R response);
protected void validRequest(P request) { if (Objects.isNull(request.getToken())) { throw new RuntimeException("token不能为空"); } if (Objects.isNull(request.getVersion())) { throw new RuntimeException("version不能为空"); }
validRequestParam(request); }
protected abstract void validRequestParam(P request);
protected abstract R getResponse(P request); }
|
基本请求
1 2 3 4 5 6 7 8 9 10
|
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class Request {
private String version;
private String token; }
|
基本响应
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class Response {
private String msg;
private int code;
private boolean success;
}
|
子类实现
第一个子类实现
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
|
4j public class OneProcessor extends <OneRequest, OneResponse> {
public OneProcessor() { ProcessorFactory.putProcess(“two”, this); }
@Override protected void afterHandle(OneResponse response) { log.info(“处理One结果: {}”, response.getOne()); }
@Override protected void validRequestParam(OneRequest request) { log.info(“校验one参数…省略……”); }
@Override protected OneResponse getResponse(OneRequest request) { String name = request.getName(); return OneResponse.builder() .one(name + “one”) .success(true) .code(0) .msg(“成功”) .build(); } }
|
第一个子类的请求
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Data @ToString(callSuper = true) @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class OneRequest extends Request {
private String name;
@Builder.Default private int a = 0;
}
|
第一个子类的响应
1 2 3 4 5 6 7 8 9 10
|
@Data @ToString(callSuper = true) @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class OneResponse extends Response {
private String one;
}
|
第二个子类实现
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
|
4j public class TwoProcessor extends <TwoRequest, TwoResponse> {
public TwoProcessor() { ProcessorFactory.putProcess(“two”, this); }
@Override protected void afterHandle(TwoResponse response) { log.info(“处理结果TWO, {}”, response); }
@Override protected void validRequestParam(TwoRequest request) { log.info(“校验TWO参数…省略……”); }
@Override protected TwoResponse getResponse(TwoRequest request) { Long id = request.getId(); return TwoResponse.builder() .two(“id为”+id) .success(true) .code(0) .msg(“成功”) .build(); } }
|
第二个子类的请求
1 2 3 4 5 6 7 8 9
|
@Data @ToString(callSuper = true) @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class TwoRequest extends Request {
private Long id; }
|
第二个子类的响应
1 2 3 4 5 6 7 8 9
|
@Data @ToString(callSuper = true) @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class TwoResponse extends Response {
private String two; }
|
扩展为工厂
有的时候我们定义的子类在Spring容器的时候由Spring定义好后,我们其实可以借用工厂模式方法,在子类初始化的时候就把子类放置在ProcessorFactory中,后续只需要根据key从中拿取即可,实际项目中用这种方式还是比较多的。
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public class ProcessorFactory {
private static Map<String, AbstractProcessor> factories = new HashMap();
public static void putProcess(String key, AbstractProcessor process) { factories.put(key, process); }
public static AbstractProcessor selectProcess(String key) { return factories.get(key); }
}
|
执行程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
4j public class TemplateMethodApplication {
public static void main(String[] args) { OneRequest oneRequest = OneRequest.builder() .version("2312312") .token("23423") .name("张三") .build(); new OneProcessor().handle(oneRequest);
log.info("--------------------------");
TwoRequest twoRequest = TwoRequest.builder() .version("2312312") .token("23423") .id(23456L) .build(); new TwoProcessor().handle(twoRequest);
} }
|
结果

总体上来讲,抽象类中定义了算法的框架,然后把部分算法步骤抽象出来供子类实现,有的时候有些方法只有个别子类会去实现,我们可以在抽象类中实现为空实现,在有需要的子类中我们可以覆盖抽象类的实现,这样避免了所有的子类都去实现,其实不关心的话都是空实现了。本示例用到了lombok的@SuperBuilder特性,可能在下载完完整的代码后会出现编译错误,这是因为Lombok的插件暂时还不支持@SuperBuilder。
模板方法模式总结
模板方法经常和其他模式混合使用,比如工厂、策略等等。其实在Spring中大量使用了模板方法模式,其实也不光在Spring中,像平时jdbcTemplate或者RedisTemplate,像这种带有Template的。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项: 为防止恶意操作,一般模板方法都加上 final 关键词。
参考
模板模式|菜鸟教程
Template method pattern
近期评论