美文网首页
JavaScript设计模式——模板方法模式

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

作者: cherry_liulei | 来源:发表于2018-05-01 14:19 被阅读5次

    模板方法(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设计模式——模板方法模式

          本文链接:https://www.haomeiwen.com/subject/hkwxrftx.html