JavaScript设计模式——模板方法模式

模板方法(Template Method)

模板方法模式是一种只需要继承就可以实现的非常简单的模式。
模板方法模式通常由两部分组成:

  • 抽象父类
  • 实现具体方法的子类
    通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。
    子类通过继承父类,也继承了整个算法结构,并且需要重写父类的方法,来实现具体的业务逻辑。

典型案例 Coffee or Tea

泡一杯咖啡的步骤:
(1)把水煮沸
(2)用沸水冲泡咖啡
(3)把咖啡倒进杯子
(4)加奶和糖
泡一杯茶的步骤:
(1)把水煮沸
(2)用沸水浸泡茶叶
(3)把茶水倒进杯子
(4)加柠檬

     var Coffee = function () { };

     Coffee.prototype.boilWater = function () {
            console.log('把水煮沸');
      };

      Coffee.prototype.brewCoffeeGrounds = function () {
            console.log('用水冲泡咖啡');
      };

      Coffee.prototype.pourInCup = function () {
            console.log('把咖啡倒进杯子');
      };

      Coffee.prototype.addSugarAndMilk = function () {
            console.log('加糖和奶');
      };

      Coffee.prototype.init = function () {
            this.boilWater();
            this.brewCoffeeGrounds();
            this.pourInCup();
            this.addSugarAndMilk();
      };

      var coffee = new Coffee();
      coffee.init();


        var Tea = function () {};

        Tea.prototype.boilWater = function () {
            console.log('把水煮沸');
        };

        Tea.prototype.steepTeaBag = function () {
            console.log('用水浸泡茶叶');
        };

        Tea.prototype.pourInCup = function () {
            console.log('把茶水倒进杯子');
        };

        Tea.prototype.addLemon = function () {
            console.log('加柠檬');
        };

        Tea.prototype.init = function () {
            this.boilWater();
            this.steepTeaBag();
            this.pourInCup();
            this.addLemon();
        };

        var tea = new Tea();
        tea.init();

使用模板方法模式重构上面代码:

        var Baverage = function () {
        };

        Baverage.prototype.boilWater = function () {
            console.log('把水煮沸');
        };

        Baverage.prototype.brew = function () {
            // 空方法,留着给子类重写
            // 为了检查子类是否重写了该方法,抛出一个异常
            throw new Error('子类必须重写brew方法');
        };

        Baverage.prototype.pourInCup = function () {
            // 空方法,留着给子类重写
            throw new Error('子类必须重写pourInCup方法');
            
        };

        Baverage.prototype.addCondiments = function () {
            // 空方法,留着给子类重写
            throw new Error('子类必须重写addCondiments方法');
            
        };

        Baverage.prototype.init = function () {
            this.boilWater();
            this.brew();
            this.pourInCup();
            this.addCondiments();
        };

        // 创建子类
        var Coffee = function(){};
        // 继承父类
        Coffee.prototype = new Baverage();
        // 重写父类的方法
        Coffee.prototype.brew = function () {
            console.log('用沸水冲泡咖啡');
        };
        Coffee.prototype.pourInCup = function () {
            console.log('把咖啡倒进杯子');
        };
        Coffee.prototype.addCondiments = function () {
            console.log('加糖和牛奶');
        };

        
        var coffee = new Coffee();
        coffee.init();

        var Tea = function () {};
        Tea.prototype = new Baverage();
        
        Tea.prototype.brew = function () {
            console.log('用水浸泡茶叶');
        };

        Tea.prototype.pourInCup = function () {
            console.log('把茶水倒进杯子');
        };

        Tea.prototype.addCondiments = function () {
            console.log('加柠檬');
        };

        var tea = new Tea();
        tea.init();

Baverage构造函数,特别像Java中的抽象类。
但JavaScript中并没有从语法层面提供对抽象类的支持。如果子类没有重写父类的方法,编译器也不会报错。最终执行时,请求会沿着原型链执行到父类的方法,所以不会报错。为了保证子类重写父类的方法,所以在父类方法中直接throw了Exception。

对于JavaScript来说,也可以不使用继承来完成以上的效果。
还可以使用高阶函数来实现,这也是很多常用组件实现的方式:

        var Baverage = function (options) {
            var boilWater = function () {
                console.log('把水煮沸');
            };

            var brew = options.brew || function(){
                throw new Error('必须传入brew方法');
            };

            var pourInCup = options.pourInCup || function(){
                throw new Error('必须传入pourInCup方法');
            };

            var addCondiments = options.addCondiments || function(){
                throw new Error('必须传入addCondiments方法');
            };

            var F= function(){};

            F.prototype.init = function(){
                boilWater();
                brew();
                pourInCup();
                addCondiments();
            };

            return F;

        };

        // 创建子类
        var Coffee = Baverage({
            brew : function () {
                console.log('用沸水冲泡咖啡');
            },
            pourInCup : function () {
                console.log('把咖啡倒进杯子');
            },
            addCondiments : function () {
                console.log('加糖和牛奶');
            },
        });
       var coffee = new Coffee();
       coffee.init();

       var Tea = Baverage({
            brew : function () {
                console.log('用水浸泡茶叶');
            },
            pourInCup : function () {
                console.log('把茶水倒进杯子');
            },
            addCondiments : function () {
                console.log('加柠檬');
            },
        });
       var tea = new Tea();
       tea.init();

你可能感兴趣的:(JavaScript设计模式——模板方法模式)