美文网首页
模板方法模式

模板方法模式

作者: 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