**
**
案例说明
我们想要手工制作一个蛋糕,假如我们不知道制作的步骤,那就可以找个蛋糕制作的模板步骤来参考制作,我们不需要去考虑哪一步应该在什么时候做,完全按照模板的步骤照搬就行了,这就是模板模式。 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、模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理。
