Template Method

概念

模板方法:Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure. 在一个操作中定义一个算法骨架,并将某些步骤推迟到子类实现。可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

算法可以理解为业务逻辑。

模板方法的作用:

  • 复用:子类都可以复用父类中模板方法定义的流程代码。如 InputStream、OutputStream、Reader、Writer,AbstractList 等。

  • 扩展:更多指框架的扩展性,类似控制反转,可以让用户不修改框架源码的情况下,定制化框架的功能。如 Java Servlet、JUnit 等。

示例

public abstract class AbstractClass {
  public final void templateMethod() {
    //...
    method1();
    //...
    method2();
    //...
  }
  
  protected abstract void method1();
  protected abstract void method2();
}

public class ConcreteClass extends AbstractClass {
  @Override
  protected void method1() {}
  
  @Override
  protected void method2() {}
}

AbstractClass demo = ConcreteClass();
demo.templateMethod();

模板方法用 final 修饰,避免子类重写;扩展点用 abstract 修饰,强迫子类实现。不过这两点都不是必须的。

源码

InputStream

AbstractList

Servlet

用户实现的扩展点:

Servlet 容器收到请求后,会找到相应的 Servlet,并调用它的 service 方法。框架的模板方法:

JUnit

JUnit 提供了一些扩展点,如 setUp(), tearDown() 等。

Callback

回调与模板模式一样也具有复用和扩展的功能。

原理

A 类事先注册某个函数 F 到 B 类,A 类在调用 B 类的 P 函数时,B 类反过来调用 A 类注册给 B 类的 F 函数,F 就叫做回调函数。

回调不仅可以用在代码设计上,还能用在高层次的架构设计上。比如用户向第三方支付系统发起支付,一般不会等到支付结果返回,而是注册回调函数(URL)给第三方支付系统,支付系统执行成功后,将结果通过回调接口返回给用户。

回调有同步回调和异步回调,同步回调更像模板模式,异步回调更像观察者模式。

示例

JdbcTemplate

Spring 提供很多 Template 类,但它们并非基于模板方法实现,而是基于 Callback 实现。

如果直接写 JDBC 代码会很冗余,比如:

加载驱动、创建连接、关闭连接等很多操作与业务无关,这些流程大多可以复用,所以 Spring 提供了 JdbcTemplate,用户代码可以变得非常简洁:

JdbcTemplate 核心的逻辑如下:

Hook

Callback 更加注重语法机制的描述,Hook 更加侧重应用的描述。Tomcat 和 JVM 都有shutdown hook,以 JVM 为例,当应用程序关闭时,会调用 ApplicationShutdownHooks 的 runHooks 方法:

比较

同步回调几乎与模板模式一致,都是在一个大的算法骨架中,自由替换其中的个别步骤,起到代码复用和扩展的目的。

实现方式:模板方法基于继承;回调基于组合。

组合优于继承,那么回调相对于模板方法的优势如下:

  • Java 只支持单继承。

  • 回调可以使用匿名类,不用事先定义类。

  • 如果一个类有多个模板方法,每个类都有对应的抽象方法,那么模板方法需要实现所有的抽象方法;而回调只需要往我们需要的模板方法中注入回调对象即可。

Last updated

Was this helpful?