设计模式——模版方法
一、首先记住什么模版方法模式(看后面的代码理解):
模版方法模式指在一个方法,里面包含了一个多步骤的算法骨架,其中一个或者多个步骤允许子类延后实现。允许子类在不修改算法的结构的
前提下,对一个或多个步骤进行自己的实现。
二、下面用代码来创建的咖啡和茶来说明:
第一种情况:
分别创建Cofee.java和Tea,里面分别都有四个步骤:
1.煮水
2.用沸水泡茶 或者 用沸水泡咖啡
3.把茶或者咖啡装进杯子
4.往杯子加入柠檬或者牛奶
package design.template; public class Cofee { void prepare(){ boilWater(); chongkaifei(); pourInCup(); addSugarAndMilk(); } //煮沸水 private void boilWater() { System.out.println("煮沸水"); } //用沸水冲咖啡 private void chongkaifei(){ System.out.println("用沸水冲咖啡"); } //倒入杯子 private void pourInCup() { System.out.println("倒入杯子"); } //加糖和牛奶 private void addSugarAndMilk(){ System.out.println("加糖和牛奶"); } } package design.template; public class Tea { void prepare(){ boilWater(); chongcha(); pourInCup(); addLemon(); } //煮水 private void boilWater(){ System.out.println("煮水"); } //用沸水冲茶 private void chongcha(){ System.out.println("用沸水冲茶"); } //把茶装进被子 private void pourInCup(){ System.out.println("装进杯子"); } //加柠檬 private void addLemon(){ System.out.println("加柠檬"); } } package design.template; import design.template3.Cofee; //测试类 public class TestTemplate { public static void main(String[] args) { new Cofee().prepare(); } }
仔细看,发现泡咖啡和泡茶两个行为其实有很多相似之处。例如第一和第三步其实都是要把水煮沸,然后把液体倒入被子。
第二种情况:
定义一个超类CaffeineBeverage,因为第一步和第三步方法被Tea和Cofee类共享,所以直接在父类实现。
而prepare()方法在每个类中都不一样,所以定义成抽象方法。
package design.template2; /** * prepare()方法在每个类中都不一样,所以定义成抽象方法。 * boilWater(),pourInCup()被两个子类所共享,所以被定义在这个超类中 * @author lindq3 * * 2017-2-15 */ public abstract class CaffeineBeverage { //因为prepare在Tea和Cofee类里面都不同,所以定义为抽象方法。在子类里面重写 abstract void prepare(); void boilWater(){ System.out.println("正在煮水"); } void pourInCup(){ System.out.println("倒入杯子"); } } package design.template2; public class Cofee extends CaffeineBeverage { void prepare(){ boilWater(); chongkaifei(); pourInCup(); addSugarAndMilk(); } //用沸水冲咖啡 private void chongkaifei(){ System.out.println("用沸水冲咖啡"); } //加糖和牛奶 private void addSugarAndMilk(){ System.out.println("加糖和牛奶"); } }
第三种情况(其中这个就是模版方法模式的实现):
进一步观察,Tea类和Cofee类除了共享第一和第三个方法外,还有一个相似的地方:就是整个泡茶,泡咖啡的“步骤相似”。于是可以考虑把prepare()方法也在父类实现。
prepare()就是一个包含多个步骤的方法,允许里面的步骤部分由父类实现,部分由子类实现。
如果需要控制boilWater()或者pourInCup()不被子类重写,也可以定义为final
public abstract class CaffeineBeverage { //因为2个子类也具备相似的步骤,把prepare法官也在父类定义。 //定义为final防止被子类重写。 public final void prepare(){ boilWater(); mixSth();//冲东西 pourInCup(); addSth();//加东西 } //具体冲什么东西由子类决定 abstract void mixSth(); //具体加东西由子类决定 abstract void addSth(); //以下2个方法为子类共有 private void boilWater() { System.out.println("煮沸水"); } private void pourInCup() { System.out.println("倒入杯子"); } }
package design.template3; public class Cofee extends CaffeineBeverage{ @Override void mixSth() { System.out.println("用沸水冲咖啡"); } @Override void addSth() { System.out.println("加糖和牛奶"); } }
第四种情况:对模板方法进行挂钩
钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。例如咖啡加不加牛奶应该由客户决定。
具体例子如下:
package design.template4; /** * 咖啡因饮料类 * 同时进一步对prepare()方法进行抽象。 * 因为不希望prepare被子类覆盖,所以定义为final类型。 * prepare()方法被成为模版方法。为什么? * 这个例子里面: * 1. prepare()是一个方法 * 2.它用作一个算法的模板,在这个例子中,算法是用来制作咖啡因饮料的。里面的每一个方法步骤都在prepare里面定义了。 * 而且有的方法是由父类提供,有的是由子类提供。 * * 简单地说,模版方法就是提供了一个算法(包含多个方法),允许子类对其中的某几个方法提供实现。 * 模版方法模式指在一个方法,里面包含了一个多步骤的算法骨架,其中一个或者多个步骤允许子类延后实现。允许子类在不修改算法的结构的 * 前提下,对一个或多个步骤进行自己的实现。 * @author lindq3 * * 2017-2-15 */ public abstract class CaffeineBeverageWithHook { public final void prepare(){ boilWater(); mixSth();//冲东西 pourInCup(); // 如果顾客“想要”调料,只有这时我们才调用addCondiments()。 if(customerWantsCondiments()){ addSth();//加东西 } } abstract void mixSth(); abstract void addSth(); private void boilWater() { System.out.println("煮沸水"); } private void pourInCup() { System.out.println("倒入杯子"); } //定义一个方法作为hook boolean customerWantsCondiments(){ return true; } } package design.template4; public class Cofee extends CaffeineBeverageWithHook{ @Override void mixSth() { System.out.println("用沸水冲咖啡"); } @Override void addSth() { System.out.println("加糖和牛奶"); } //定义一个方法作为hook //客户不想要加东西 boolean customerWantsCondiments(){ return false; } }
三、总结使用模版方法模式的优势:
四、参考:
《 Head first设计模式 》学习笔记 – 模板方法模式
posted on 2017-02-15 01:44 lukelin1989 阅读(173) 评论(0) 编辑 收藏 举报