模板方法
定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
图示模板方法
图示分析 : 蓝色虚线部分表示一个算法的骨架, 黑色虚线表示算法中定义的固定执行动作, 而椭圆虚线表示由具体的子类才知道应该在此步骤时执行何种操作, 即[将一些步骤延迟到子类中而不改变算法的结构]
演示代码
展示图示的简单实现
-
锤子类
- execute()方法定义为final, 算法骨架不可被子类更改
- 调用者知道如何使用锤子, 传入[UseHammer]
public class Hammer {
// 锤子类型
private String type;
public Hammer(String type) {
this.type = type;
}
final void execute(UseHammer useHammer) {
System.out.println("============================");
// 开始制作锤子
startMake();
// "获得锤子
getHammer();
// 使用锤子
useHammer.use(this);
// 归还锤子
returnHammer();
System.out.println("============================");
}
public void startMake() {
System.out.println("开始制作锤子!");
}
public void getHammer() {
System.out.println("获得锤子!");
}
public void returnHammer() {
System.out.println("归还锤子!");
}
@Override
public String toString() {
return "Hammer{" +
"type='" + type + '\'' +
'}';
}
}
-
使用锤子回调接口
- 推荐使用JDK8以上匿名类实现此回调
public interface UseHammer {
/**
* 回调方法.
* @param hammer 锤子參數
*/
void use(Hammer hammer);
}
-
调用测试
- 调用端知道使用锤子的逻辑
@Test
public void useHammer() {
// 木匠使用
UseHammer carpenterUse = (u) -> {
System.out.println("使用" + u + "制作家具");
};
// 美队使用
UseHammer captainAmericaUse = (u) -> {
System.out.println("使用" + u + "消灭灭霸");
};
// 雷神使用
UseHammer thunderGodUse = (u) -> {
System.out.println("用个锤子");
};
Hammer hammer = new Hammer("雷神之锤");
// 锤子的使用
hammer.execute(carpenterUse);
hammer.execute(captainAmericaUse);
hammer.execute(thunderGodUse);
}
-
输出结果
- 符合图示
优秀框架模板方法示例
模板方法 - RedisTemplate.execute(RedisCallback action)
图示
还有如kafakaTemplate, jdbcTemplate等优秀框架, 根据他们的命名, 我们也可以模板方法去解读.
总结 : 优秀开源框架, 根据命名规则去分析用到的设计模式
模板方法 - JDK提供数组排序算法Arrays.sort(Object[] a)
对象数组的比较, 红线所示为用户定义行为, 具体每个对象与另一对象(都实现Comparable接口)的比较由具体的对象来控制.
总结
模板方法设计模式设计原则
什么是好莱坞法则呢?简单点说,就是“不要找我们,我们会联系你”。模板方法模式很好的体现了这一点,做为父类的模板会在需要的时候,调用子类相应的方法,也就是由父类来找子类,而不是让子类来找父类。这是一种反向的控制结构,按照通常的思路,是子类找父类才对,也就是应该是子类来调用父类的方法,因为父类根本就不知道子类,而子类是知道父类的,但是在模板方法模式里面,是父类来找子类,所以是一种反向的控制结构
学习收获
代码设计时, 参考开源框架中类似的实现
根据框架内部源码命名, 匹配到对应的设计模式
多写代码 多看源码 多想