模板方法模式的定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。属于行为型模式。
模板方法模式的本质就是抽象封装流程、处理通用实现、具体子类可以对其中的一些流程节点进行重写不同的实现逻辑。
模板方法模式的结构:模板方法模式主要包含以下2个角色。
- 抽象模板(Abstract Class):抽象模板类,负责给出一个算法的轮廓和骨架。
- 具体实现(Concrete Class):具体实现类,对模板中的某些步骤节点进行重写。
在模板方法模式中,除了包含模板方法和每个步骤的方法外,还包含钩子方法。钩子方法的目的是干预执行流程,使用钩子方法可以控制某些步骤的执行,使流程更灵活。
模板方法模式的通用实现:
//抽象模板
public abstract class AbstractClass {
//模板方法
public final void TemplateMethod() {
SpecificMethod();
if(needMethod1()){
abstractMethod1();
}
abstractMethod2();
}
//具体方法
protected void SpecificMethod() {
System.out.println("抽象类中的具体方法被调用...");
}
//抽象方法1
protected abstract void abstractMethod1();
//抽象方法2
protected abstract void abstractMethod2();
protected boolean needMethod1(){
return true;
}
}
//具体模板
public class ConcreteClass extends AbstractClass{
private boolean needMethod1;
public ConcreteClass(boolean needMethod1){
this.needMethod1 = needMethod1;
}
@Override
protected void abstractMethod1() {
System.out.println("抽象方法1的实现被调用...");
}
@Override
protected void abstractMethod2() {
System.out.println("抽象方法2的实现被调用...");
}
@Override
protected boolean needMethod1() {
return needMethod1;
}
}
//测试类
public class TemplateMethodTest {
public static void main(String[] args) {
AbstractClass tm = new ConcreteClass(false);
tm.TemplateMethod();
}
}
模板方法模式的结构图:
模板方法模式的应用实例:我们平时去银行办理业务一般要经过以下4个流程:取号、排队、办理业务、对工作人员进行评价,其中取号、排队和评价是固定的,可以在抽象类具体实现,每个人都一样,但是办理业务可能是存款、取款或者转账等等,可以延迟到子类中实现。如果前面没人就不需要排队,所以排队不是必须流程,可以使用钩子方法控制。
//抽象类
public abstract class AbstractBusiness {
private int number;
public final void doBusinessTemplate(){
//取号
getNumber();
//前面有人就要排队
if(havePerson()){
lineUp();
}
//办业务
doBusiness();
//评价
evaluate();
}
private void getNumber() {
Random random = new Random();
number = random.nextInt(5);
if(number>1){
System.out.println("你是"+number+"号,前面有"+(number-1)+"人!");
}else{
System.out.println("你是"+number+"号,请直接去办理业务!");
}
}
private boolean havePerson() {
if(number<2){
return false;
}
return true;
}
private void lineUp(){
System.out.println("前面有"+(number-1)+"人,请耐心等待!");
}
protected abstract void doBusiness();
protected abstract void evaluate();
}
//转账
public class TransferAccounts extends AbstractBusiness{
@Override
protected void doBusiness() {
System.out.println("我要转账!!!");
}
@Override
protected void evaluate() {
System.out.println("5星好评!!!");
}
}
//存钱
public class SaveMoney extends AbstractBusiness{
@Override
protected void doBusiness() {
System.out.println("我要存钱!!!");
}
@Override
protected void evaluate() {
System.out.println("4星好评!!!");
}
}
//测试类
public class Test {
public static void main(String[] args) {
AbstractBusiness ta = new TransferAccounts();
ta.doBusinessTemplate();
AbstractBusiness sm = new SaveMoney();
sm.doBusinessTemplate();
}
}
上面实例的结构图:
模板方法模式的优点:
- 在抽象父类中提取了公共逻辑代码,提高代码的复用性。
- 通过子类扩展新的行为,提高代码的扩展性,符合开闭原则。
模板方法模式的缺点:
- 每个不同的实现都要定义一个子类,导致类的个数增加,设计也更加抽象,间接地增加了系统的复杂度。
- 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。
模板方法模式的应用场景:
- 算法的整体步骤很固定,但其中个别步骤易变时,可以使用模板方法模式,将易变部分抽象出来,供子类实现。
- 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。
- 当需要控制子类的扩展时,模板方法只在特定点调用钩子方法,这样就只允许在这些点进行扩展。