Template - 模版设计模式

22 阅读2分钟

什么是模版模式?

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

优点

  1. 封装不变部分,扩展可变部分。
  2. 提取公共代码,便于维护。
  3. 行为由父类控制,子类实现。

缺点

每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景

  1. 有多个子类共有的方法,且逻辑相同,功能目的相同。
  2. 重要的、复杂的方法,可以考虑作为模板方法,提升系统可维护性。

示例

如下为模版模式的一个示例,React 当中的所有生命周期钩子方法其实就是典型的模版模式,组件要继承 React.Component。组件的生命周期是固定的,不会允许外部随意修改,定义这些钩子函数的作用就是给自定义组件,在特定生命周期节点上,扩展能力用的。

class MyComponent extends React.Component {

    componentDidMount() {
        console.log("组件已完成挂载。")
    }
    
    render() {
        console.log("组件渲染。")
        return <div>"Hello World"</div>;
    }
}

另外一个想到的应用是 Java 的 Tread 类,封装了绝大部分复杂逻辑,包括对 JVM native 方法 start0 的调用,还有 Thread 生命周期管理等等。我们在创建新线程时,我们需要定义一个实现了 Runnable 接口的自定义类,然后以静态代理的方式交给 Thread 类去启动,我们只需要关心 run 方法内的实现即可。

public class Main {

    public static void main(String[] args) {
        System.out.println("Main Start");
        new Thread(new MyThread()).start();
        System.out.println("Main End");
    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("Hello world");
        }
    }
}

Output:

Main Start
Main End
Hello world

在真实的业务需求中,模版模式应用非常广泛,例如下单接口中通常需要进行数据校验,创建订单,发送邮件等一系列的操作,为此我们可以定制一个下单流程的模版,把以上各环节写成抽象方法,而具体的实现留个各个不同订单类型自己去实现。


interface BookingService {
    default void book(String userName, String email) {
        validate(userName);
        createOrder(userName);
        sendNotification(email);
    }
    void validate(String userName);
    void createOrder(String userName);
    void sendNotification(String email);
}

class MovieBookingService implements BookingService {
    @Override
    public void validate(String userName) {
        System.out.println(String.format("[%s] has passed validation", userName));
    }
    @Override
    public void createOrder(String userName) {
        System.out.println(String.format("Movie order for user: [%s] has been created", userName));
    }
    @Override
    public void sendNotification(String email) {
        System.out.println(String.format("Movie order email: [%s] has been sent", email));
    }
}

public class Main {
    public static void main(String[] arg) {
        BookingService service = new MovieBookingService();
        service.book("Lucien", "lucien.chen@123.com");
    }
}

Output:

[Lucien] has passed validation
Movie order for user: [Lucien] has been created
Movie order email: [lucien.chen@123.com] has been sent