模板模式在诸多模式中算是比较简单的一个,即便一个新手,也能很快的上手和使用。虽然简单,但合理的在项目中使用带来的好处可不小。软件设计中有个很重要的原则:DRY(Don‘t Repeat Yourself),重复有很多种,比如代码重复,逻辑重复,而模板模式的最拿手的就是消除逻辑重复。
我们先看一下模板模式的定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中去实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。只要你学习过任何一门面向对象语言,那么理解上面的定义肯定不是问题。
来看看模式的UML类图:
AbstractClass是一个抽象类,其中templateMethod是一个final方法,封装了具体的算法实现步骤、过程,其内部调用了其它方法。abstractMethod1与abstractMethod2是抽象方法,其具体实现由具体的子类决定,这样子类就可以在不改变算法结构的情况下,重新定义算法中的某些步骤。值得一提的是hook方法,它是一个钩子方法,在父类中会提供一个默认的实现,子类可以有选择的决定是否要覆盖钩子方法。简单而言,钩子让子类有机会修改算法中的某些步骤,是否使用钩子完全取决于业务。
我们来看一个例子。
饮料 | 牛奶 | 咖啡 |
1. 把杯子洗干净。 2. 把水煮沸。 3. 把饮料放入杯子。 4. 把开水倒入杯中。 5. 加调料。 6. 搅拌。 |
1. 把杯子洗干净。 2. 把水煮沸。 3. 把奶粉放入杯子。 4. 把开水倒入杯中。 5. 加糖。 6. 搅拌。 |
1. 把杯子洗干净。 2. 把水煮沸。 3. 把咖啡放入杯子。 4. 把开水倒入杯中。 5. 加糖、伴侣。 6. 搅拌。 |
饮料(Beverage是一个抽象类,make方法封装了饮料的制作流程,但具体制作什么饮料,加不加调料、加什么调料由给子类去决定,addCondiment方法是一个钩子,默认什么都不做。
public abstract class Beverage { public final void make() { System.out.println("把杯子洗干净。"); System.out.println("把水煮沸。"); this.addBeverage(); System.out.println("把水倒入杯中。"); this.addCondiment(); System.out.println("搅拌。"); } protected abstract void addBeverage(); protected void addCondiment() { //默认什么调料都不加。 } }
public class Milk extends Beverage { @Override protected void addBeverage() { System.out.println("把奶粉倒入杯口。"); } } public class Coffee extends Beverage { @Override protected void addBeverage() { System.out.println("把咖啡倒入杯口。"); } @Override protected void addCondiment() { System.out.println("加糖和咖啡伴侣。"); } }
public static void main(String[] args) { Beverage milk = new Milk(); Beverage coffee = new Coffee(); System.out.println("做牛奶......"); milk.make(); System.out.println("\n做咖啡......"); coffee.make(); } 做牛奶...... 把杯子洗干净。 把水煮沸。 把奶粉倒入杯口。 把水倒入杯中。 搅拌。 做咖啡...... 把杯子洗干净。 把水煮沸。 把咖啡倒入杯口。 把水倒入杯中。 加糖和咖啡伴侣。 搅拌。
JDK中有哪些使用模板模式的部分?
像Collections.sort、Arrays.sort等方法,都需要一个实现Comparator接口的对象来决定如何比较对象(实现compare方法);
又如File.listFiles方法需要一个实现FileFilter接口的对象来决定如何过滤文件(通过实现accept方法),在JDK中类似的场景还有很多,这里就不一一例举了。
原文地址:http://blog.csdn.net/oyl822/article/details/43581465