模板方法模式

238 阅读2分钟

模板方法模式

模板方法模式是一种使用继承实现的简单模式。

模板方法模式由两部分组成,第一部分是抽象父类,第二部分是具体实现子类。

具体实现子类需要对抽象父类定义的方法进行重写。

JavaScript 模仿继承实现

使用 vue-cli 可以创建 vue2 项目或者 vue3 项目,创建项目的过程大致一样,只是需要选择不同的 vue 版本,这个时候可以用模板方法模式来封装变化。

function createVueApp() {}
createVueApp.prototype.execCreateCommand = function() {
    console.log('execCreateCommand');
};
createVueApp.prototype.chooseVueVersion = function() {
    throw new Error('请重写函数');
};
createVueApp.prototype.init = function() {
    this.execCreateCommand();
    this.chooseVueVersion();
};

function createVue2App() {}
createVue2App.prototype = new createVueApp();
createVue2App.prototype.chooseVueVersion = function() {
    console.log('选择 vue2');
};
createVue2App.prototype.init();

function createVue3App() {}
createVue3App.prototype = new createVueApp();
createVue3App.prototype.chooseVueVersion = function() {
    console.log('选择 vue3');
};
createVue3App.prototype.init();

用 JavaScript 实现模板方法模式具有一些缺陷。第一就是 JavaScript 没有继承,JavaScript 中使用 prototype 原型链实现伪继承,更准确的说法应该是委托;第二是 JavaScript 中没有抽象方法和类型系统,于是不能确定子类是否重写了父类方法。这个问题由两个解决方案,第一是鸭子类型检查,第二是实例代码中由父类抛出错误。

JavaScript 高阶函数实现

由于函数在 JavaScript 中是一等公民,可以当成参数传递。所以可以使用高阶函数的形式实现模板方法模式。

function createVueApp(param) {
    const execCreateCommand = function() {
        console.log('execCreateCommand');
    };
    const chooseVueVersion =
        param.chooseVueVersion ||
        function() {
            throw new Error('请重写函数');
        };

    const F = function() {};

    F.prototype.init = function() {
        execCreateCommand();
        chooseVueVersion();
    };

    return F;
}

const createVue2App = createVueApp({
    chooseVueVersion: function() {
        console.log('选择 vue2');
    },
});

const createVue3App = createVueApp({
    chooseVueVersion: function() {
        console.log('选择 vue3');
    },
});

模板方法模式其实就是封装不变的部分到父类,变化的部分由子类自己实现。他是一种典型的通过封装系统变化提高系统扩展性的设计模式。在 JavaScript 中,使用高阶函数实现模板方法模式是一种更好的选择。