在深入了解之前,容许我先扯远一点。
作为一个进化论的反对者,假设这个世界是上帝用代码创造的。那么上帝创造生命的时候可能就用到了模版方法模式。看看他是怎么在生命构造器中声明模版方法的:
var Life = function(){ } Life.prototype.init = function(){ this.DNA复制(); this.出生(); this.成长(); this.衰老(); this.死亡(); } this.prototype.DNA复制 = function(){ &*$%&^%^&(&(&(&&(^^(*) //看不懂的代码 } Life.prototype.出生 = function(){ } Life.prototype.成长 = function(){ } Life.prototype.衰老 = function(){ } Life.prototype.死亡 = function(){ }
其中DNA复制是预先定义的算法中不变部分. 所有子类都不能改写它. 如果需要我们可以写成protected的类型.
而其他的函数在父类中会被先定义成一个空函数(钩子). 然后被子类重写,这就是模版方法中所谓的可变的步骤。
假设有个子类哺乳动物类继承了Life类.
var Mammal = function(){ } Mammal.prototype = Life.prototype; //继承Life
然后重写出生和衰老这两个钩子函数.
Mammal.prototope.出生 = function(){ '胎生() } Mammal.prototype.成长 = function(){ //再留给子类去实现 } Mammal.prototope.衰老 = function(){ 自由基的过氧化反应() } Life.prototype.死亡 = function(){ //再留给子类去实现 } //再实现一个Dog类 var = Dog = function(){ } //Dog继承自哺乳动物. Dog.prototype = Mammal.prototype; var dog = new Dog(); dog.init();
至此,一只小狗的生命会依次经历DNA复制,出生,成长,衰老,死亡这几个过程。这些步骤早在它出生前就决定了。所幸的是,上帝没有安排好它生命的所有细节。它还是能通过对成长函数的重写,来成为一只与众不同的小狗。
举个稍微现实点的例子,游戏大厅中的所有游戏都有登录,游戏中,游戏结束这几个过程,而登录和游戏结束之后弹出提示这些函数都是应该公用的。
那么首先需要的是一个父类。
var gameCenter = function(){ } gameCenter.ptototype.init = function(){ this.login(); this.gameStart(); this.end(); } gameCenter.prototype.login= function(){ //do something } gameCenter.prototype.gameStart= function(){ //空函数, 留给子类去重写 } gameCenter.prototype.end= function(){ alert ( "欢迎下次再来玩" ); }
接下来创建一个斗地主的新游戏, 只需要继承gameCenter然后重写它的gameStart函数.
var 斗地主 = function(){ } 斗地主.prototype = gameCenter.prototype; //继承 斗地主.prototype.gameStart = function(){ //do something } (new 斗地主).init();
这样一局新的游戏就开始了.
十一 中介者模式
中介者对象可以让各个对象之间不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
打个比方,军火买卖双方为了安全起见,找了一个信任的中介来进行交易。买家A把钱交给中介B,然后从中介手中得到军火,卖家C把军火卖给中介,然后从中介手中拿回钱。一场交易完毕,A甚至不知道C是一只猴子还是一只猛犸。因为中介的存在,A也未必一定要买C的军火,也可能是D,E,F。
银行在存款人和贷款人之间也能看成一个中介。存款人A并不关心他的钱最后被谁借走。贷款人B也不关心他借来的钱来自谁的存款。因为有中介的存在,这场交易才变得如此方便。
中介者模式和代理模式有一点点相似。都是第三者对象来连接2个对象的通信。具体差别可以从下图中区别。
代理模式:
中介者模式
代理模式中A必然是知道B的一切,而中介者模式中A,B,C对E,F,G的实现并不关心.而且中介者模式可以连接任意多种对象。
切回到程序世界里的mvc,无论是j2ee中struts的Action. 还是js中backbone.js和spine.js里的Controler. 都起到了一个中介者的作用.
拿backbone举例. 一个mode里的数据并不确定最后被哪些view使用. view需要的数据也可以来自任意一个mode. 所有的绑定关系都是在controler里决定. 中介者把复杂的多对多关系, 变成了2个相对简单的1对多关系.