设计模式学习 —— 模板方法
模板模式:封装了一个算法步骤,并允许子类为一个或者多个步骤方法提供实现。模板模式可以在子类不改变算法结构的情况下,重新定义算法中的某些步骤。
固定的东西成为模板在抽象父类中。
个性化的步骤在子类中实现。
身边的模板模式:
我们用的很多框架都是用模板来完成的:
1、排序鸭子 :Arrays.sort() 这个就是个模板方法,Ducks 这个类实现 Comparable 接口
2、自定义控件
3、
编写模板方法类
要点:1、设计成抽象类的原因是这个类中有未实现的方法,之所以不设计成接口,是因为这个类中有固定实现的方法(是不是 Java8 中可以用接口来实现,因为 Java8 有接口默认实现方法);
2、整个模板方法 prepareBeverageTemplate() 设计成 final ,体现了模板的固定性。
既然叫“模板”,意思是按照固定的模式去做一件事情,所以模板这件事情上不能留给客户端空间,否则就失去了模板的意义。
3、固定的步骤,已经实现的方法,使用 private 修饰,子类不能修改,这一部分是模板类中固定的部分;
4、须要让子类完成的步骤,应该使用 protected 修饰,延迟到子类实现;
5、关注到钩子函数,钩子函数使用 protected 修饰,并且不是抽象的方法,是一个具体的方法,子类可以根据须要去重写。
/**
* Created by Liwei on 2016/7/4.
* 抽象基类,为所有子类提供一个算法框架
* 提神饮料
*/
public abstract class RefreshBeverage {
/**
* 制备饮料的模板方法
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate() {
// 步骤 1 将水煮沸
boilWater();
// 步骤 2 泡制饮料
brew();
// 步骤 3 将饮料倒入杯中
pourInCup();
// isCustomerWantsCondiments() 是一个具体的方法
if (isCustomerWantsCondiments()) {
// 步骤 4 加入调味料
addCondiments();
}
}
/**
* 基本方法,将水煮沸
* 这是一个通用的,没有差别的方法,
* 设置访问权限为私有,向下屏蔽细节
*/
private void boilWater() {
System.out.println("固定方法--将水煮沸");
}
/**
* 基本方法,将饮料倒入杯中
*/
private void pourInCup() {
System.out.println("固定方法--将饮料倒入杯中");
}
/**
* 须要在子类中可见,延迟到子类实现具体细节
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
/**
* 加入调味料
*/
protected abstract void addCondiments();
/**
* Hook,钩子函数,提供一个默认的或者空的实现
* 具体子类可以自行决定是否挂钩,以及如何挂钩
* 询问用户是否加入调料
*
* @return
*/
protected boolean isCustomerWantsCondiments() {
return true;
}
}
编写两个实现类
1、茶类(加调料)
注意:须要重写加调料 isCustomerWantsCondiments() 方法。
public class Tea extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("特殊方法--用 80 度的水冲泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("特殊方法--加入柠檬");
}
/**
* 子类通过覆盖的形式选择挂载钩子函数,
* 钩子函数让子类更加灵活
* @return
*/
@Override
protected boolean isCustomerWantsCondiments(){
return false;
}
}
2、咖啡类(不加调料)
不加调料是默认实现,所以无须覆盖 isCustomerWantsCondiments() 方法。
public class Coffee extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("特殊方法--用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("特殊方法--加入糖和牛奶");
}
}
编写测试方法:
public class Main {
public static void main(String[] args) {
RefreshBeverage tea = new Tea();
tea.prepareBeverageTemplate();
System.out.println("------ 愉快的分割线 ------");
RefreshBeverage coffee = new Coffee();
coffee.prepareBeverageTemplate();
}
}