美文网首页
模板方法模式

模板方法模式

作者: bby365 | 来源:发表于2018-07-04 19:25 被阅读0次

    由两部分组成:第一部分是抽象父类;第二部分是具体的实现子类。
    金典例子:Coffee or Tea

    // 1. 创建父类,添加原型公用方法
    var Beverage = function(){};
    Beverage.prototype.boilWater = function(){
        console.log( '把水煮沸' );
    };
    
    Beverage.prototype.brew = function(){}; // 空方法,应该由子类重写
    Beverage.prototype.pourInCup = function(){}; // 空方法,应该由子类重写
    Beverage.prototype.addCondiments = function(){}; // 空方法,应该由子类重写
    Beverage.prototype.init = function(){
        this.boilWater();
        this.brew();
        this.pourInCup();
        this.addCondiments();
    };
    
    // 2.创建子类,并原型继承父类,重写父类的抽象方法
    
    // 2-1 创建子类
    var Coffee = function(){};
    Coffee.prototype = new Beverage();
    // 2-2 根据需求,重写父类方法
    Coffee.prototype.brew = function(){
        console.log( '用沸水冲泡咖啡' );
    };
    Coffee.prototype.pourInCup = function(){
        console.log( '把咖啡倒进杯子' );
    
    };
    Coffee.prototype.addCondiments = function(){
        console.log( '加糖和牛奶' );
    };
    
    // 3 子类实例化,调用执行
    var Coffee = new Coffee();
    Coffee.init();
    

    上面代码中Beverage.prototype.init就是模板方法,因为它封装了子类的算法框架,也规定了它们的执行顺序。


    现在,有另外一种场景:父类封装的算法框架适用于大多数子类,但有些“个性化”的子类,不想执行其中的某个步骤,怎么办?
    钩子方法:

    // 原来的模板方法
    Beverage.prototype.init = function(){
        this.boilWater();
        this.brew();
        this.pourInCup();
        this.addCondiments();
    };
    
    // 改进方案:
    // 1 添加钩子方法(hook),决定执行步骤
    Beverage.prototype.init = function(){
        this.boilWater();
        this.brew();
        this.pourInCup();
        if ( this.customerWantsCondiments() ){ // 如果挂钩返回true,则需要调料
            this.addCondiments();
        }
    }
    // 2 子类重写钩子方法
    CoffeeWithHook.prototype.customerWantsCondiments = function(){
        return window.confirm( '请问需要调料吗?' );
    };
    

    如果不用继承,怎么实现模板方法模式?
    为了方便描述,还是使用父类和子类概念。

    1. 父类封装算法框架,并接受参数,更改重写方法。
    2. 子类需要实例化,所以父类要返回一个构造函数。
    3. 如果仅仅是事项功能,不需要第2条,返回一个init()就行。
    // 1. 抽象函数
    var Beverage = function( param ){
        var boilWater = function(){
            console.log( '把水煮沸' );
        };
        var brew = param.brew || function(){
            throw new Error( '必须传递brew 方法' );
        };
        var pourInCup = param.pourInCup || function(){
            throw new Error( '必须传递pourInCup 方法' );
        };
        var addCondiments = param.addCondiments || function(){
            throw new Error( '必须传递addCondiments 方法' );
        };
        var F = function(){};
        F.prototype.init = function(){
            boilWater();
            brew();
            pourInCup();
            addCondiments();
        };
        return F;
    };
    // 2. 返回具体的子类
    var Coffee = Beverage({
        brew: function(){
            console.log( '用沸水冲泡咖啡' );
        },
        pourInCup: function(){
            console.log( '把咖啡倒进杯子' );
        },
        addCondiments: function(){
            console.log( '加糖和牛奶' );
        }
    });
    // 3. 子类实例化,调用
    var coffee = new Coffee();
    coffee.init();
    

    直接返回init

    // 1. 抽象函数
    var Beverage = function( param ){
        var boilWater = function(){
            console.log( '把水煮沸' );
        };
        var brew = param.brew || function(){
            throw new Error( '必须传递brew 方法' );
        };
        var pourInCup = param.pourInCup || function(){
            throw new Error( '必须传递pourInCup 方法' );
        };
        var addCondiments = param.addCondiments || function(){
            throw new Error( '必须传递addCondiments 方法' );
        };
        // 仅仅实现功能,直接返回init
        var init = function(){
            boilWater();
            brew();
            pourInCup();
            addCondiments();
        };
        return init;
    };
    // 2. 返回具体的子类
    var Coffee = Beverage({
        brew: function(){
            console.log( '用沸水冲泡咖啡' );
        },
        pourInCup: function(){
            console.log( '把咖啡倒进杯子' );
        },
        addCondiments: function(){
            console.log( '加糖和牛奶1231313' );
        }
    });
    // 3.直接调用
    Coffee()
    

    相关文章

      网友评论

          本文标题:模板方法模式

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