设计模式之模板方法模式

1,001 阅读4分钟

本篇文章是设计模式专题的第九篇文章,我会将遇到的设计模式都一一总结在该专题下,我会把自己对每一种设计模式的感悟写下来,以及在实际工作中我们该如何去灵活应用这些设计模式,欢迎大家关注。本篇文章我们就来讲一讲模板方法模式。

模板方法模式的简单介绍

模板方法模式是行为型模式的一种,用来定义一个操作中的算法骨架。

如何去理解算法骨架呢?也就是说我们在设计这个算法的时候,就清晰的知道了算法所需要的关键步骤,而且确定了这些步骤的执行顺序,但是某些具体的步骤无法确定,或者是具体的步骤需要根据场景做调整

模板方法其实更强调于因地制宜,同样的一个方法,不同场景得到的结果是不一样的。

最简单的语言描述,就是通过模板方法去调用一系列的子方法,子方法可以定义为抽象方法,可以交给不同的子类去实现,从而实现高度的可扩展性。

模板方法模式的类图:

image.png

模板方法模式的具体实现思路

  • 通过抽象类定义共性的方法,特性的方法通过抽象方法表示,定义模板方法(算法骨架)。
  • 通过不同的子类实现差异化。
  • 模板方法中可以通过钩子函数增加灵活性。

模板方法模式的具体实现方案

// 抽象类
public abstract class AbstractTemplate {
    // 模板方法
    // 为防止恶意操作,一般情况下模板方法都加上final关键词。
    public final void templateMethod() {
        // 这几个方法的调用及顺序构成算法骨架
        // 抽象方法(特异性方法)
        abstractMethod1();
        // 钩子函数
        HookMethod1();
        if (HookMethod2()) {
            // 公共方法
            SpecificMethod();
        }
        // 抽象方法
        abstractMethod2();
    }
    // 具体方法,将共性的实现交由抽象类实现
    public void specificMethod() {
        // 具体逻辑
    }
    // 钩子方法也可以在抽象类中实现,然后通过子类改写
    // 钩子方法1
    public void HookMethod1() {
    }
    // 钩子方法2
    public boolean HookMethod2() {
        return true;
    }
    // 抽象方法1
    public abstract void abstractMethod1();
    // 抽象方法2
    public abstract void abstractMethod2();
}
​
// 具体实现类
public class ConcreteTemplate extends AbstractTemplate {
    @Override
    public void abstractMethod1() {
        // 具体实现
    }
    @Override
    public void abstractMethod2() {
        // 具体实现
    }
    // 方法重写
    @Override
    public void hookMethod1() {
        // 具体实现
    }
    // 方法重写
    @Override
    public boolean hookMethod2() {
        return false;
    }
}

模板方法模式的优缺点

优点

  • 封装了不变部分,扩展可变部分。
  • 提取了公共的部分代码,便于代码复用。
  • 通过增加子类可以很好的扩展算法,符合开闭原则。

缺点

  • 对于不同的实现都需要增加一个子类,这会导致系统的类增多
  • 模板方法模式设计更加抽象,增加了系统实现的复杂度。
  • 通过子类方法影响父类方法,这导致一种反向的控制结构,它提高了代码阅读的难度。
  • 基于继承关系自身的特点,父类添加新的抽象方法,所有子类都需要同步修改一遍。

模板方法模式的适用场景

  1. 算法的整体步骤很固定,但是其中一些方法需要根据场景不同,进行不同的实现,我们就可以将易变的抽象出来,交由子类实现。
  2. 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。
  3. 当需要控制子类的扩展部分是否执行时,可以在特定的方法前调用钩子操作,这样就增强了模板方法的灵活性。

模板方法模式总结

模板方法模式注重解决的问题是复杂算法,固定算法套路,场景不同实现不同。遇到这三个特点的场景,我们就可以考虑使用模板方法去实现或者是优化重构。

Spring中的AbstractApplicationContext中的refresh()就是模板方法模式。