定义
模板方法模式在一个方法中定义类一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
解释
甲打开了一个app,买了一张汽车票,乘坐汽车,到了泰山。
乙打开了一个app,买了一张船票,乘船,到了泰山。
丙打开了一个app,买了一张机票,乘坐飞机,到了泰山。
骨架:某人,打开了一个app,买了xx,乘坐xx,到了泰山。
子类:甲乙丙提供部分算法的具体实现。
类图
伪代码
public abstract class Travel{
public final void travel(){// 算法步骤
openApp();
buyTicket();
takeVehicle();
to();
}
pulbic final void openApp(){// 限定只能打开指定的app 子类不能覆盖
System.out.println("open app");
}
public abstract void buyTicket();//子类实现
public abstract void takeVehicle();//子类实现
public final void to(){
System.out.println("to 泰山");
}
}
public class 甲 extends Travel{
public void buyTicket(){ // 子类实现
System.out.println("buy car tickey");
}
public void takeVehicle(){// 子类实现
System.out.println("take car);
}
}
public class 乙 extends Travel{
public void buyTicket(){ // 子类实现
System.out.println("buy ship tickey");
}
public void takeVehicle(){// 子类实现
System.out.println("take ship);
}
}
示例:
Travel travel = new 甲();
travel.travel();
travel = new 乙();
travel.travel();
描述
- Travel就是一个算法模板,定义了一些列的算法步骤,其中部分步骤是抽象的,需要子类实现。整个Travel的算法结构是固定的。
模板方法中的钩子
钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,有子类自行决定。
钩子其实也是算法步骤中的一个步骤,只是有些特殊,用于控制作用。
钩子伪代码
public abstract class Travel{
public final void travel(){// 算法步骤
openApp();
if(isGoodWeather()){// 好天气才出行
buyTicket();
takeVehicle();
to();
}
}
pulbic final void openApp(){// 限定只能打开指定的app 子类不能覆盖
System.out.println("open app");
}
public abstract void buyTicket();//子类实现
public abstract void takeVehicle();//子类实现
public final void to(){
System.out.println("to 泰山");
}
public boolean isGoodWeather(){//钩子方法,默认好天气
return true;
}
}
public class 甲 extends Travel{
public void buyTicket(){ // 子类实现
System.out.println("buy car tickey");
}
public void takeVehicle(){// 子类实现
System.out.println("take car);
}
public void isGoodWeather(){
return false;
}
}
public class 乙 extends Travel{
public void buyTicket(){ // 子类实现
System.out.println("buy ship tickey");
}
public void takeVehicle(){// 子类实现
System.out.println("take ship);
}
}
示例:
Travel travel = new 甲();
travel.travel();// 甲的天气不好,不能出行
travel = new 乙();
travel.travel();// 乙的天气好,能出行
- isGoodWeather()其实也是算法的一个步骤,只是超类提供类默认实现,子类选择性实现。
- 钩子的作用是让子类有机会对模板方法中的步骤作出反应,作出一部分决定。
哪些方法需要定义为抽象方法
- 当你的子类“必须”提供算法中某个方法或步骤的实现时,就使用抽象方法,如果算法是可选的,就用钩子。
模板方法与策略模式的却别
- 概括来说,策略模式,使用对象组合,组合的类实现了整个算法;模板方法,使用继承,子类实现整个算法步骤中的一部分步骤细节。
- 模板方法定义了一个算法的大纲,由子类定义其中某些步骤的内容,这么一来,在算法中的个别步骤可以有不同的实现细节,但是算法的结构依然维持不变。
- 策略模式,定义了一个算法家族,并让这些算法可以互换。正因为每一个算法都被封装起来了,所以客户可以轻轻一地使用不同的算法。
总结
- 模板方法定义了算法的步骤,把这些步骤的实现延迟到子类。
- 模板方法模式为我们提供了一种代码复用的重要技巧。
- 模板方法的抽象类可以定义具体方法、抽象方法和钩子。
- 抽象方法由子类实现。
- 钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要覆盖它。
- 为了防止子类改变模板方法中的算法,可以将模板方法声明为final。
- 好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用低层模块。
- 策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
- 工厂方法是模板方法的一种特殊版本。