模板方法:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 T模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:抽象类(AbstractClass): 定义抽象的原语操作(primitive operation) ,具体的子类将重定义它们以实现一个算法, 实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义
具体子类 (ConcreteClass): 实现原语操作以完成算法中与特定子类相关的步骤。
例子:
到山下的水泥厂要预订水泥,需要三个流程:提交预订申请,申报数量,交订金,其中申请与订金两个步骤都是要有的,区别不同的是申报数量的不同,此时村民与建筑工地都需要向水泥厂提交申请,
类图:
代码:
/**
* 水泥厂买水泥的流程,其具体步骤是确定的通过模板方法buyProcess来确定
* 分 预订,数量,交订金三部分,不同的部分是数量上的差别
* @author wang
*/
public abstract class BuyCement {
public final void buyProcess(){
order();//预订
number();//购买数量
subscription();//交订金
}
public abstract void number();
public void order(){
System.out.println("提交预订申请");
}
public void subscription(){
System.out.println("交订金1000元");
}
}
/**
* 村民买水泥,10袋就够了
* @author wang
*/
public class VillagerBuyCement extends BuyCement {
@Override
public void number() {
System.out.println("买十袋水泥");
}
}
/**
* 建筑工地买水泥,来上100袋
* @author wang
*/
public class BuildSiteBuyCement extends BuyCement {
@Override
public void number() {
System.out.println("买100袋水泥");
}
}
public class Client {
public static void main(String[] args){
VillagerBuyCement villager = new VillagerBuyCement();
villager.buyProcess();
BuildSiteBuyCement buildSite = new BuildSiteBuyCement();
buildSite.buyProcess();
}
}
运行结果如下:
在模板方法中使用挂钩
定义一个空的实现方法(hook),由子类决定是否要覆盖它。
因为水泥厂与建筑工地属于长期业务合作伙伴,因此建筑工地的预订可以赠送几袋水泥或者不用交押金了,
先看赠送几袋水泥的代码
/**
* 水泥厂买水泥的流程,其具体步骤是确定的通过模板方法buyProcess来确定
* 分 预订,数量,交订金三部分,不同的部分是数量上的差别
* @author wang
*/
public abstract class BuyCement {
public final void buyProcess(){
order();//预订
number();//购买数量
subscription();//交订金
hook();//挂钩
}
public void hook(){};
public abstract void number();
public void order(){
System.out.println("提交预订申请");
}
public void subscription(){
System.out.println("交订金1000元");
}
}
/**
* 建筑工地买水泥,来上100袋
* @author wang
*/
public class BuildSiteBuyCement extends BuyCement {
@Override
public void number() {
System.out.println("买100袋水泥");
}
@Override
public void hook() {
System.out.println("长期业务伙伴,赠送5袋水泥");
}
}
运行结果如下:
如果工地不用交押金了,代码如下:
/**
* 水泥厂买水泥的流程,其具体步骤是确定的通过模板方法buyProcess来确定
* 分 预订,数量,交订金三部分,不同的部分是数量上的差别
* @author wang
*/
public abstract class BuyCement {
public final void buyProcess(){
order();//预订
number();//购买数量
//挂钩决定是否交订金
if(hook()){
subscription();//交订金
}
}
public boolean hook(){
return true;
}
public abstract void number();
public void order(){
System.out.println("提交预订申请");
}
public void subscription(){
System.out.println("交订金1000元");
}
}
/**
* 建筑工地买水泥,来上100袋
* @author wang
*/
public class BuildSiteBuyCement extends BuyCement {
@Override
public void number() {
System.out.println("买100袋水泥");
}
@Override
public boolean hook() {
return false;
}
}
运行结果如下:
模板方法的优点:
1:利于重复代码的复用,将子类的重复代码上移到抽象类中。
2:模板方法定义算法的步骤,具体实现在具体子类中,这样会更灵活。
模板方法模式与策略模式的区别:
模板方法模式只改变算法的一部分,并且用继承来实现算法的改变,策略模式采用的委托来改变的是整个算法,但两者可以互相替换。