一. 简述
定义一个操作中的算法的骨架,而将一些可变部分的实现延迟到子类中。使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定的步骤。
属于行为型模式。
举例:
我们假设一个饮品店要制作各种果汁,我们知道制作果汁的过程都是相似的,比如先加水,再加水果,再加冰......只是具体配料不同而已,我们也明白这些步骤的顺序是不能改变的(我假设不能吧),如果这个店招了一个服务员,这个服务员做事马马虎虎,老是忘记制作果汁的步几个骤或者弄乱了制作顺序,导致经常制作失败,给小店带来损失,老板招不到别人就只好继续用他,为了减少损失,老板写了一个详细的制作步骤在一张纸上,其中只是步骤的名称,要求该服务员每次制作之前都要看一遍按上面的步骤来做,根据具体制作果汁的种类来实现具体的步骤。
把模板方法从这里边揪出来:
我们把老板给店员写的那个纸条抽象成一个超类,在上面声明一些子类必须实现的方法(抽象方法),而在超类中不需实现,再定义一个方法来安排各个操作的步骤顺序,然后在创建一些子类来继承父类,在这些子类中必须实现超类的方法(也就是店员必须按照老板的给的指示一步一步都实现),各个子类也不必再重新定义一个方法来安排整个制作过程,因为可以利用默认从超类继承的制作过程方法。
二. 组成
- 抽象模板角色(AbstractClass):给出一个具体的方法,称为模版方法,它定义了整个算法的逻辑骨架,而算法的可变部分定义为抽象方法或者提供默认实现,将实现延迟到子类中。
方法分为:模板方法(Templete Method)和基本方法(primitive Method)。
模板方法(TempleteMethod): 抽象模板中定义的具体方法,通常定义为final,从而保证了子类的逻辑永远由父类所控制。
基本方法(primitive Method)分为: 抽象方法,具体方法,钩子方法。
a. 抽象方法: 抽象模板中定义为抽象方法,由子类实现。
b. 具体方法: 抽象模板中提供默认实现。
c. 钩子方法:抽象模板中定义并提供默认实现(通常是空实现),在子类中覆盖或扩展。
- 具体模板角色(ConcreteClass):实现抽象模板所定义的可变的抽象操作。
三. UML类图
四. 基本代码
abstract class FruitJuice
{
public abstract void AddWater(); //加水
public abstract void AddFruit(); //加水果
public abstract void AddIceBlock(); //加冰
public abstract void AddLemonSlice(); //加柠檬片
public void MakeJuice() //制作果汁
{
AddWater();
AddFruit();
AddIceBlock();
AddLemonSlice();
System.out.println("果汁已经做好!");
}
}
class OrangeJuice extends FruitJuice{ //橘子汁
public void AddWater()
{
System.out.println("加30ML的水");
}
public void AddFruit()
{
System.out.println("加橘子");
}
public void AddIceBlock()
{
System.out.println("加冰块");
}
public void AddLemonSlice()
{
System.out.println("不加柠檬片");
}
}
class GrapeJuice extends FruitJuice{ //葡萄汁
public void AddWater()
{
System.out.println("加50ML的水");
}
public void AddFruit()
{
System.out.println("加葡萄");
}
public void AddIceBlock()
{
System.out.println("不加冰块");
}
public void AddLemonSlice()
{
System.out.println("加柠檬片");
}
}
public class TemplatePattern {
public static void main(String args[])
{
OrangeJuice juice1=new OrangeJuice();
GrapeJuice juice2=new GrapeJuice();
System.out.println("开始制作橘子汁\n");
juice1.MakeJuice();
System.out.println("\n开始制作葡萄汁\n");
juice2.MakeJuice();
}
}
五. 优缺点
优点:
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。其实这可以说是一种好的编码习惯了。
- 控制子类扩展。模板方法只在特定点调用操作,这样就只允许在这些点进行扩展。