**
设计模式(十二)之模板模式
**
-
案例说明
我们想要手工制作一个蛋糕,假如我们不知道制作的步骤,那就可以找个蛋糕制作的模板步骤来参考制作,我们不需要去考虑哪一步应该在什么时候做,完全按照模板的步骤照搬就行了,这就是模板模式。
Cake是一个抽象类,包含了抽象方法purchase,具体的已经实现的方法有prepare、mix、baking、addCream,钩子方法isPurchase,模板方法make;其子类ChocolateCake、FruitsCake、IceCreamCake分别去继承Cake,实现Cake的抽象方法purchase。抽象的蛋糕类,模板方法make可以用final修饰。
public abstract class Cake {
abstract void purchase();
void prepare(){
System.out.println("准备制作蛋糕的工具");
}
void mix(){
System.out.println("搅拌鸡蛋、奶油及各种原材料");
}
void baking(){
System.out.println("烘焙蛋糕");
}
void addCream(){
System.out.println("加奶油装饰");
}
// 钩子方法
boolean isPurchase(){
return true;
}
// 模板方法
final void make(){
if(isPurchase()){
purchase();
}
prepare();
mix();
baking();
addCream();
}
}
具体的蛋糕子类
public class ChocolateCake extends Cake{
@Override
void purchase() {
System.out.println("采购巧克力粉");
}
}
public class FruitsCake extends Cake{
@Override
void purchase() {
System.out.println("采购水果");
}
}
重写抽象蛋糕类中的钩子方法,假设我们已经有了冰淇淋原材料,那采购方法我们就不做任何的操作,此处体现出钩子方法的灵活性和可配置性。
public class IceCreamCake extends Cake{
@Override
void purchase() {
}
@Override
boolean isPurchase() {
return false;
}
}
客户端
public class Client {
public static void main(String[] args) {
Cake cake = null;
cake = new ChocolateCake();
// 按照模板来制作巧克力蛋糕
cake.make();
System.out.println("————————————————————————————————————————————————");
cake = new FruitsCake();
// 按照模板来制作水果蛋糕
cake.make();
System.out.println("————————————————————————————————————————————————");
cake = new IceCreamCake();
// 按照模板来制作冰淇淋蛋糕
cake.make();
}
}
测试
D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=56512:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar;D:\dev_tools\repository\cglib\cglib\3.3.0\cglib-3.3.0.jar;D:\dev_tools\repository\org\ow2\asm\asm\7.1\asm-7.1.jar com.wd.template.Client
采购巧克力粉
准备制作蛋糕的工具
搅拌鸡蛋、奶油及各种原材料
烘焙蛋糕
加奶油装饰
————————————————————————————————————————————————
采购水果
准备制作蛋糕的工具
搅拌鸡蛋、奶油及各种原材料
烘焙蛋糕
加奶油装饰
————————————————————————————————————————————————
准备制作蛋糕的工具
搅拌鸡蛋、奶油及各种原材料
烘焙蛋糕
加奶油装饰
Process finished with exit code 0
-
总结
1、算法只存在于一个地方,也就是在父类中,容易修改。需要修改算 法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改;
2、实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接
使用;
3、既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现;
4、该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大;
5、一般模板方法都加上final关键字, 防止子类重写模板方法;
6、模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理。