模板方法模式定义了一套算法调用步骤的模板,通过继承,子类可以对一个或多个步骤提供实现。当需要扩展时,只需要添加子类即可,而且子类可以复用父类的代码。
模板方法模式的类图如下:
下面以泡茶和冲咖啡为例
抽象出泡茶和冲咖啡的咖啡因饮料类
/** 定义了模板方法的类,抽象出咖啡和茶的咖啡因饮料类**/public abstract class CaffeineBeverage{ /** 模板方法,调用一系列的步骤,实现制作饮料的步骤 **/ public final void prepareRecipe() { boilWater(); brew(); pourInCup(); if(custormerWantCondiments()) addCondiments(); } /** 由于把水煮沸的步骤对于任何饮料都是一样的,则父类直接实现该方法 **/ public void boilWater() { System.out.println("boil water"); } public abstract void brew(); public abstract void addCondiments(); public void pourInCup() { System.out.println("pour In cup"); } /** 子类可以选择实现的“钩子”方法 **/ public boolean custormerWantCondiments() { return true; }}
Tea类
/** 继承了模板方法的类Tea,没有实现钩子方法**/public class Tea extends CaffeineBeverage{ public void brew() { System.out.println("Steeping the tea"); } public void addCondiments() { System.out.println("adding lemon"); } }
Coffee类
import java.io.*;/** 继承了模板方法的类Coffee类**/public class Coffee extends CaffeineBeverage{ public void brew() { System.out.println("Dripping Coffee through filter"); } public void addCondiments() { System.out.println("adding sugar"); } /** 子类可以选择实现的“钩子”方法 **/ public boolean custormerWantCondiments() { String answer=getUserInput(); if(answer.equals("y")) { return true; } return false; } private String getUserInput() { String answer=null; System.out.println("would you like milk and sugar in your coffee?"); BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); try { answer=in.readLine(); } catch (IOException e) { e.printStackTrace(); } if(answer==null) { return "n"; } return answer; }}
测试类
public class Test{ public static void main(String[] args) { Coffee coffee=new Coffee(); System.out.println("Making coffee...."); coffee.prepareRecipe(); Tea tea=new Tea(); System.out.println("Making tea...."); tea.prepareRecipe(); }}
运行结果
可以看出模板方法定义的步骤里面有三种不同类型的方法:
1.由父类直接实现的方法:比如上例中的boilWater和pourInCup方法,对于Coffee和Tea来说,都是一样的,所以可以复用,可以定义为final
2.由子类实现的方法:比如上例中的brew方法
3.子类可选择实现的方法,比如上例中的customerWantCondiments()方法。
由模板方法模式中的“钩子”,可以引申出一个设计原则——“好莱坞原则”,“别电话给我,我会打电话给你”,就是说,低层组件可以将自己挂钩到系统上,但是由高层组件决定什么时候和怎样使用这些底层组件,所以对于高层组件来说,其对待低层组件的方式是“别调用我,我会调用你们”。像上例中的customerWantCondiments()方法,就是由子类实现,父类调用。
模板方法的应用之一是用模板方法排序。
Arrays类中提供了一个sort方法,sort方法实际上调用了一个私有的mergeSort()方法
mergeSort方法是一个模板方法,我们可以通过改变比较的条件实现自己的排序,我们需要实现的是Comparable接口中的compareTo()方法。
比如说我们要将学生按成绩排序。
写一个Student类,实现Comparable接口
public class Student implements Comparable { public int score; public String name; public Student(String name,int score) { this.name=name; this.score=score; } public int compareTo(Object object) { Student otherStudent=(Student)object; if(this.score>otherStudent.score) { return 1; } else if(this.score==otherStudent.score) { return 0; } else { return -1; } }}
测试类
import java.util.*;public class TestSort{ public static void main(String[] args) { Student[] stu={ new Student("qing",100), new Student("chen",90), new Student("zhou",80), new Student("ddd",50) }; System.out.println("before sorting...."); display(stu); System.out.println("after sorting...."); Arrays.sort(stu); display(stu); } public static void display(Student[] stu) { for(Student s:stu) { System.out.println(s.name+"\t"+s.score); } }}
运行结果是
模板方法模式,策略模式,工厂方法模式的比较