模板方法模式有两部分组成
抽象父类具体实现的子类通常是在父类中定义算法骨架和一些公共的方法,子类继承父类方法的基础上,不修改算法骨架,重新定义父类中算法的某些实现步骤。
我们去银行取钱、存钱、办卡等业务的时候,都需要三大步骤:
排队取号;办理具体的业务;服务评价。然后这个步骤可以抽取到父类中去实现整体的步骤(算法骨架),其中第一步排队取号和第三步服务评价是公共的方法,可以在父类中实现,第二步办理具体业务在不同的子类来实现
3.1 存钱
首先我们来看下银行存钱业务,一般步骤如下:
排队取号;存钱;服务评价。通过以下代码,我们就完成了去银行办理存钱的业务
var Deposit = function () {}; Deposit.prototype.takeNumber = function() { console.log('排队取号'); }; Deposit.prototype.depositMoney = function() { console.log('存钱'); }; Deposit.prototype.serviceEvaluation = function() { console.log('服务评价'); }; Deposit.prototype.init = function() { this.takeNumber(); this.depositMoney(); this.serviceEvaluation(); console.log('完成银行业务办理'); }; var deposit = new Deposit(); deposit.init();3.2 取钱
接下来是去银行取钱业务(当然现在都是大笔业务才需要柜台,小笔金额可以直接在ATM操作哈~~),一般步骤如下:
排队取号;取钱;服务评价。通过以下的代码,我们就完成了去银行办理取钱的业务
var Withdraw = function () {}; Withdraw.prototype.takeNumber = function() { console.log('排队取号'); }; Withdraw.prototype.withdrawMoney = function() { console.log('取钱'); }; Withdraw.prototype.serviceEvaluation = function() { console.log('服务评价'); }; Withdraw.prototype.init = function() { this.takeNumber(); this.withdrawMoney(); this.serviceEvaluation(); console.log('完成银行业务办理'); }; var withdraw = new Withdraw(); withdraw.init();3.3 分离共同点
现在我们分别完成了存钱和取钱的银行业务,通过思考和比较,我们发现去银行办理业务的流程是大同小异的,如
存钱取钱排队取号排队取号存钱取钱服务评价服务评价通过对比发现以下不同点:
办理的业务不同。不管是取钱还是存钱,我们都可以把它抽象为银行业务。那么整体的业务流程步骤大概是以下三步:
排队取号;办理银行业务;服务评价。我们创建一个父类银行业务类来处理银行业务办理的整个过程,不管是取钱还是存钱或者是办卡,我们都用handleBusiness的方法来表示,具体代码如下:
var BankBusiness = function () {}; BankBusiness.prototype.takeNumber = function() { console.log('排队取号'); }; BankBusiness.prototype.handleBusiness = function() { // 空方法 由子类重写 }; BankBusiness.prototype.serviceEvaluation = function() { console.log('服务评价'); }; BankBusiness.prototype.init = function() { this.takeNumber(); this.handleBusiness(); this.serviceEvaluation(); console.log('完成银行业务办理'); };创建存钱子类,并让它继承银行业务类:
var Deposit = function () {}; Deposit.prototype = new BankBusiness();接下来要重写抽象父类中的一些方法,排队取号和服务评价可以直接使用父类BankBusiness中的takeNumber方法和serviceEvaluation方法,handleBusiness方法都需要在Deposit子类中重写,代码如下:
Deposit.prototype.handleBusiness = function () { console.log('存钱'); } var deposit = new Deposit(); deposit.init();至此我们的Deposit类已经完成了,当调用deposit对象的init方法时,由于deposit对象和Deposit构造器的原型prototype上都没有对应的init方法,所以该请求会顺着原型链,被委托给Deposite的“父类”BankBusiness原型上的init方法。而BankBusiness.prototype.init方法中已经规定好了银行办理业务的顺序,所以我们能成功地办理取钱业务,代码如下:
BankBusiness.prototype.init = function() { this.takeNumber(); this.handleBusiness(); this.serviceEvaluation(); console.log('完成银行业务办理'); };通过上面的例子,我们可以得知BankBusiness.prototype.init就是我们说的模板方法。 BankBusiness.prototype.init被称为模板方法的原因是,该方法中封装了子类的算法框架,它作为一个算法的模板,指导子类以何种顺序去执行哪些方法。BankBusiness.prototype.init方法中,算法内的每一个步骤都清楚地展示在我们眼前。