模板方法模式
在我们的功能设计中,通常一些功能是由一系列步骤来完成的,这些步骤的次序基本一致,但是它们的实现可能完全不同。比如我们打算买一部手机,那么流程基本为浏览、下单、支付、收货四个步骤,浏览下单可以线上下下,支付可以现金、转账,收货可以立刻取货、邮寄等。可以看出,步骤是固定的,但是实现方法多样。
那么为了提高代码的复用性和灵活性,我们可以使用模板方式来设计此类功能。模板方法模式是结构最简单的行为型设计模式,它是一种类行为模式,在其结构中只存在父类与子类的继承关系;它将一系列复杂的流程实现封装在一系列基本的方法中,抽象父类中提供了一个成为模板方法的方法来定义这些基本方法的执行顺序,而通过子类来覆盖或者实现某些关键的基本方法,因而达到了不同执行效果的目的。
定义
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
- 模板方法:定义在抽象类中的方法,调用基本方法,规定了基本方法的调用顺序完成特定的功能
- 基本方法:实现复杂算法的基本步骤,可以由子类覆盖或者实现来完成特定功能,被模板方法调用
- 钩子方法:通过子类对钩子方法的覆盖或者实现,模板方法可以决定对某些方法的执行或拒绝
结构
- AbstractClass(抽象类):抽象类中定义了一系列的基本方法,这些基本方法可以是具体的也可以是抽象的,由子类覆盖或者实现。同时抽象类也定义了一个模板方法,用于定义了一个算法框架,方法中按顺序调用了基本方法。
- ConcreteClass(具体子类):抽象类的子类,用于实现父类中声明的基本方法来完成某些特定的基本功能,也可以覆盖父类中的具体基本方法。
实例
public abstract class DailyItinerary {
public void execute() {
this.getUp();
this.eatBreakfast();
this.eatLunch();
this.eadDinner();
this.sleep();
}
public abstract void getUp();
public abstract void eatBreakfast();
public abstract void eatLunch();
public abstract void eadDinner();
public abstract void sleep();
}
public class WorkingDayDailyItinerary extends DailyItinerary{
@Override
public void getUp() {
System.out.println("7点起床");
}
@Override
public void eatBreakfast() {
System.out.println("吃包子");
}
@Override
public void eatLunch() {
System.out.println("公司午餐");
}
@Override
public void eadDinner() {
System.out.println("公司晚餐");
}
@Override
public void sleep() {
System.out.println("11点睡觉");
}
}
public class RestDayDailyItinerary extends DailyItinerary {
@Override
public void getUp() {
System.out.println("10点起床");
}
@Override
public void eatBreakfast() {
System.out.println("不吃早饭");
}
@Override
public void eatLunch() {
System.out.println("下厨");
}
@Override
public void eadDinner() {
System.out.println("大餐");
}
@Override
public void sleep() {
System.out.println("12点睡觉");
}
}
public class Test {
public static void main(String[] args) {
DailyItinerary di = new WorkingDayDailyItinerary();
di.execute();
}
}
优点
- 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,并且不会影响算法的执行顺序
- 实现了代码复用,将公共行为提取出来,通过子类实现了不同的行为
- 可以通过钩子方法来实现子类对父类的控制
- 更换和增加新的子类十分方便,每个子类定义了各自的算法,复合单一职责原则和开闭原则
适用场景
- 多种算法有固定的执行套路,但是内部的实现细节不同
- 各个子类实现中有公共的行为可以被提取出来
- 通过子类反控某个方法是否执行