前的话语

  面向对象的筹划原则,可以说每种设计模式都是为吃代码迎合其中一个或多个条件要产出的,
它们本身既融入了设计模式之中,给面向对象编程指明了系列化。适合javascript开发的计划标准包括是纯任务规范、最少知识标准化和开花封闭原则。本文将详细介绍面向对象的统筹条件

 

纯任务规范

  就一个好像而言,应该只是发生一个引她生成的因。在javascript中,需要用到类似的状况并无顶多,单一任务规范更多地是受用在目标或措施级别及

  单一任务规范(SRP)的职责被定义为“引起变化之案由”。如果有有限单思想去改写一个措施,那么这个方法就拥有两独任务。每个职责都是浮动之一个轴线,如果一个方法承担了了多之天职,那么当需求的转移过程遭到,需要改写这个措施的可能就进一步老。此时,这个艺术一般是一个休平稳之法门,修改代码总是一样件危险的事务,特别是当半个任务耦合在一起的下,一个职责发生变化可能会见潜移默化到任何任务的贯彻,造成意外的毁伤,这种耦合性得到的是小内聚和脆弱的规划。因此,SRP原则反映为:一个目标(方法)只开同样起事情

  SRP原则在群设计模式中还负有广大的运,例如代理模式、迭代器模式、单例模式及装饰者模式

【代理模式】

  通过长虚拟代理的方,把预加载图片的天职放到代理对象中,而本体仅仅负责向页面被添加img标签,这吗是她极原始之天职

  myImage负责往页面被添加img标签:

var myImage = (function(){
    var imgNode = document.createElement( 'img' );
    document.body.appendChild( imgNode );
    return {
        setSrc: function( src ){

            imgNode.src = src;
        }
    }
})();

  proxyImage负责预加载图片,并在预加载完成之后将要提交本体 myImage:

var proxyImage = (function(){
    var img = new Image;
    img.onload = function(){
        myImage.setSrc( this.src );
    }
    return {
        setSrc: function( src ){
            myImage.setSrc( 'file://loading.gif' );
            img.src = src;
        }
    }
})();
proxyImage.setSrc( 'http://test.jpg' );

  将添加img标签的职能跟预加载图片的任务分开放到片只目标吃,这点儿独对象分别还仅仅发一个让涂改的动机。在它分别发生变更的时,也非会见潜移默化另外的靶子

【迭代器模式】

  有这样同样截代码,先遍历一个会师,然后朝页面中补充加有div,这些div的innerHTML分别对应集合里的素:

var appendDiv = function( data ){
  for ( var i = 0, l = data.length; i < l; i++ ){ 
    var div = document.createElement( 'div' ); 
    div.innerHTML = data[ i ]; 
    document.body.appendChild( div );
  }
};
appendDiv( [ 1, 2, 3, 4, 5, 6 ] );

  这实际是一模一样段老常见的代码,经常用来ajax请求后,在回调函数中举历ajax请求返回的数码,然后于页面被渲染节点。appendDiv函数本来只是当渲染数据,但是于此她还承担了遍历聚合对象data的天职。如果发同一龙cgi返回的data数据格式从array变成了object,那所有历data的代码就会见冒出问题,必须反化for
in的方式,这时候要去修改appendDiv里的代码,否则因为遍历方式的变动,导致未可知尽如人意通往页面被补充加div节点

  有必不可少将整历data的职责提取出,这多亏迭代器模式之含义,迭代器模式供了平栽方法来拜会聚合对象,而休用暴露者目标的里表示。

  当把迭代聚合对象的天职单独封装在each函数中后,即使之后还要增加新的迭代方式,只需要修改each函数即可,appendDiv函数不见面吃连累,代码如下:

var each = function( obj, callback ) {
    var value,
    i = 0,
    length = obj.length,
    isArray = isArraylike( obj ); // isArraylike 函数未实现
    if ( isArray ) { // 迭代类数组
        for ( ; i < length; i++ ) {
            callback.call( obj[ i ], i, obj[ i ] );
        }
    } else {
        for ( i in obj ) { // 迭代object 对象
            value = callback.call( obj[ i ], i, obj[ i ] );
        }
    }
    return obj;
};

var appendDiv = function( data ){
    each( data, function( i, n ){
        var div = document.createElement( 'div' );
        div.innerHTML = n;
        document.body.appendChild( div );
    });
};

appendDiv( [ 1, 2, 3, 4, 5, 6 ] );
appendDiv({a:1,b:2,c:3,d:4} );

【单例模式】

  下面是均等段子代码

var createLoginLayer = (function(){
    var div;
    return function(){
        if ( !div ){
            div = document.createElement( 'div' );
            div.innerHTML = '我是登录浮窗';
            div.style.display = 'none';
            document.body.appendChild( div );
        }
        return div;
    }
})();

  现在将管理单例的天职及创造登录浮窗的任务分别封装在片单主意里,这半只章程好单独变化而互不影响,当其连接在同步的上,就到位了创建唯一登录浮窗的力量,下面的代码显然是双重好的做法:

var getSingle = function( fn ){ // 获取单例
    var result;
    return function(){
        return result || ( result = fn .apply(this, arguments ) );
    }
};
var createLoginLayer = function(){ // 创建登录浮窗
    var div = document.createElement( 'div' );
    div.innerHTML = '我是登录浮窗';
    document.body.appendChild( div );
    return div;
};

var createSingleLoginLayer = getSingle( createLoginLayer );
var loginLayer1 = createSingleLoginLayer();
var loginLayer2 = createSingleLoginLayer();
alert ( loginLayer1 === loginLayer2 ); // 输出: true

【装饰者模式】

  使用装饰者模式时,通常让类或者目标同开始独自拥有局部基础之任务,更多的职责在代码运行时被动态装饰到目标方面。装饰者模式可啊对象动态增加职责,从旁一个角度来拘禁,
这为是分别职责的等同栽办法

  下面将多少反馈的功力独立在一个函数里,然后拿此函数动态装饰到工作函数方面:

<button tag="login" id="button">点击打开登录浮层</button>
<script>
    Function.prototype.after = function( afterfn ){
        var __self = this;
        return function(){
            var ret = __self.apply( this, arguments );
            afterfn.apply( this, arguments );
            return ret;
        }
    };
    var showLogin = function(){
        console.log( '打开登录浮层' );
    };
    var log = function(){
        console.log( '上报标签为: ' + this.getAttribute( 'tag' ) );

    };
    document.getElementById( 'button' ).onclick = showLogin.after( log );
// 打开登录浮层之后上报数据

  SRP原则是颇具规则被极简便也是无比为难对使用的基准有。要明了的是,并无是拥有的任务都该一一分离。一方面,如果随着需求的变型,有半点独任务总是又转,那便无需分离他们。比如在ajax请求的时候,创建xhr对象同发送xhr请求几连接在一道的,那么创建xhr对象的职责以及发送xhr请求的天职就是从不必要分开。另一方面,职责的浮动轴线仅当其确定会发生变化时才拥有意义,即使片个任务都为耦合在一起,但它还从来不发反之兆,那么可能没有必要主动分离它们,在代码用重构的时节重新拓展分离为不迟

  在人数的健康思维中,总是习惯性地把同组有关的行放到一起,如何对地分离职责不是一致桩易的工作。在事实上开发中,因为种种原因违反SRP的气象并无丢掉见。比如jQuery的attr等方法,就是明显违背SRP原则的做法。jQuery的attr是个可怜巨大的不二法门,既当赋值,又承担取值,这对jQuery的拥护者来说,会带动有艰难,但对此jQuery的用户来说,却简化了用户的利用。在方便性与稳定之间如果生一部分增选。具体是选方便性还是安定团结,并没标准答案,而是如取决于具体的应用环境

  SRP原则的亮点是下跌了单个类或者目标的复杂度,按照职责将对象说成重粗之粒度,这促进代码的复用,也造福开展单元测试。当一个任务需要转移的时,不见面影响及另外的任务。但SRP原则吗发生部分缺点,最强烈的是会增加编制代码的复杂度。当以职责将目标说成重有些之粒度之后,实际上为增大了这些目标之间相关联的难度

 

起码知识标准化

  最少知识标准化(LKP)说之是一个软件实体应当尽可能少地及其他实体发生相互作用。这里的软件实体是一个广义的定义,不仅囊括对象,还连系统、类、模块、函数、变量等

  某部队遭受的将得开有散兵坑。下面是瓜熟蒂落任务的平栽方法:将军好通知上校让他为来少校,然后于少校找来上尉,并受上尉通知一个军士,最后军士唤来一个战士,然后命令战士挖掘有散兵坑。这种艺术充分破绽百出,不是也?不过,还是事先来拘禁一下这个进程的等价代码:

gerneral.getColonel(c).getMajor(m).getCaptain(c).getSergeant(s).getPrivate(p).digFoxhole();

  让代码通过如此长之消息链才能够不辱使命一个职责,这虽像受将通过那么基本上麻烦的步调才能够令别人打散兵坑一样荒谬!而且,这长达链中任何一个目标的反都见面潜移默化整条链的结果。最有或的凡,将军好根本不怕未见面设想挖散兵坑这样的底细信息。但是如果用军真的设想了之题目吧,他必定会打招呼某个军官:“我莫关心这个工作怎么完成,但是若得命令人去开掘散兵坑。”

  单一任务规范指导我们管对象划分成于小之粒度,这可增长对象的只是复用性。但尤其多的目标中或会见生错综复杂的关联,如果改动了内一个目标,很可能会见影响及与它相引用的其它对象。对象与对象耦合在一起,有或会见稳中有降它们的只是复用性。

  最少知识标准化要求我们以设计程序时,应当尽量减少对象中的相互。如果简单独目标期间不必彼此直接通信,那么就半只目标就不用来直接的互动关系。常见的做法是引入一个路人对象,来担负这些目标期间的通信作用。如果局部目标要往其他一对目标发起呼吁,可以经过外人对象来转发这些请求

  最少知识标准化于设计模式中体现得最为多的地方是中介者模式以及外观模式

【中介者模式】

  在世界杯中打足球彩票,如果没有博彩公司当中介,上千万之总人口合算赔率和胜负绝对是无容许的业务。博彩公司当作中介,每个人都仅仅和博彩公司发关系,博彩公司会见依据所有人数之投注情况测算好赔率,彩民们赢了钱就是起博彩公司以,输了钱就赔给博彩公司。中介者模式很好地体现了起码知识标准化。通过加一个中介者对象,让所有的有关对象还经过中介者对象来通信,而未是互为引用。所以,当一个目标来改变时,只待通知中介者对象即可

【外观模式】

  外观模式要是为子系统中之同一组接口提供一个平的界面,外观模式定义了一个高层接口,这个接口使子系统尤其容易用

  外观模式的图是指向客户挡一组子系统的复杂。外观模式对客户提供一个简约好用之高层接口,高层接口会管客户的呼吁转发给子系统来成功具体的力量实现。大多数客户还好透过请外观接口来达成访问子系统的目的。但每当平段落用了外观模式之先后中,请求外观并无是劫持的。如果外观不能够满足客户的个性化需要,那么客户为堪择通过外观来一直访问子系统

  以全自动洗衣机的一致键洗衣按钮举例,这个一键洗衣按钮就是一个外观。如果是老式洗衣机,客户若手动选项浸泡、洗衣、漂洗、脱水这4独步骤。如果这种洗衣机被淘汰了,新式洗衣机的淘洗方式产生了移,那还得上新的淘洗方式。而自动洗衣机的补很明显,不管洗衣机中如何发展,客户若操作的,始终就是一个一键浆的按钮。这个按钮就是啊同一组子系统所创办的外观。但只要一致键洗衣程序设定的默认漂洗时间是20分钟,而客户要这漂洗时间是30分钟,那么客户自然好选取通过一键洗衣程序,自己手动来决定这些“子系统”运转。外观模式容易与平常的包裹实现混淆。这二者都打包了一些物,但外观模式之主要是概念一个高层接口去包一组“子系统”。子系于C++或者Java中指的凡同样组类的集纳,这些看似相互协作可以整合系统受到一个相对独立的有。在javascript中便不会见了多地考虑“类”,如果将外观模式映射到javascript中,这个分系至少应该负的是平组函数的集结

  最简单易行的外观模式应该是类似下面的代码:

var A = function(){
  a1();
  a2();
}
var B = function(){
  b1();
  b2();
}
var facade =function(){
  A();
  B();
}
facade();

  许多javascript设计模式的图书还是文章好把jQuery的$.ajax函数当作外观模式之兑现,这是勿相宜的。如果$.ajax函数属于外观模式,那几有的函数都好给称之为“外观模式”。问题是一向没有艺术通过$.ajax“外观”去直接用该函数着之某平段子话

  现在再次来瞧外观模式及最少知识标准化中的干。外观模式之企图至关重要出有限碰

  1、为同样组子系统提供一个简约方便的拜会入口

  2、隔离客户与复杂子系统之间的沟通,客户无用去矣解子系统的细节。从第二点来,外观模式是相符最少知识标准化的

  封装在老大老程度达发表的凡数码的隐没。一个模块或者目标可以将内部的数量还是实现细节隐藏起来,只暴露必要之接口API供外界看。对象期间免不了有联系,当一个目标要引用另外一个目标的时候,可以给对象只是暴露必要之接口,让对象期间的关联限制于极端小之限定之内。同时,封装也就此来限制变量的作用域。在javascript中对变量作用域的确定是:

  1、变量在大局声明,或者当代码的旁岗位隐式申明(不用var),则该变量在全局可见;

  2、变量在函数内显式申明(使用var),则当函数内可见。把变量的可见性限制在一个尽量小的限量外,这个变量对其它非系模块的震慑就是更是小,变量被改写和来冲突之时机吗尤为小。这为是广义的卓绝少知标准化的相同种植体现

  假设要编制一个负有缓存效果的精打细算乘积的函数function
mult(){},需要一个靶var cache =
{}来保存已经算过之结果。cache对象显然只是对mult有因此,把cache对象在mult形成的闭包中,显然比拿它置身全局作用域更加适宜,代码如下:

var mult = (function(){
    var cache = {};
    return function(){
        var args = Array.prototype.join.call( arguments, ',' );
        if ( cache[ args ] ){
            return cache[ args ];
        }
        var a = 1;
        for ( var i = 0, l = arguments.length; i < l; i++ ){

            a = a * arguments[i];
        }
        return cache[ args ] = a;
    }
})();
mult( 1, 2, 3 ); // 输出: 6

  虽然守最小知识标准化减少了对象期间的靠,但为出或增加有大幅度到难维护的旁观者对象。跟单纯任务规范一致,在其实支出中,是否选择让代码符合最少知识标准化,要基于实际的条件来定

 

绽开封闭原则

  于面向对象的次设计着,开放——封闭原则(OCP)是无比着重之均等长准。很多上,一个先后有所可以的计划,往往说明它们是契合开放——封闭原则的。开放——封闭原则的概念如下:软件实体(类、模块、函数)等该是可扩展的,但是不得修改

  假设我们是一个特大型Web项目的护人员,在接手这个类型时,发现她曾经拥有10万履行以上的javascript代码和数百独JS文件。不久晚接过了一个初的需要,即在window.onload函数中打印出页面中之拥有节点数量。打开文本编辑器,搜索来window.onload函数在文书中之职,在函数内部添加以下代码:

window.onload=function(){
  //原有代码略
  console.log(document.getElementsByTagName('*').length);
};

  在列需求变化的长河中,经常会面找到相关代码,然后改写其。这如是本的事体,不转代码怎么满足新的需求呢?想使推而广之一个模块,最常用之道自是改其的源代码。如果一个模块不允许修改,那么她的表现时是原则性的。然而,改动代码是一律种危险的所作所为,也许还赶上过bug越改越多之景象。刚刚改好了一个bug,但是以当无意识被掀起了其余的bug

  如果手上的window.onload函数是一个持有500行代码的特大型函数,里面密布在各种变量和陆续的作业逻辑,而急需而不但是打印一个log这么简单。那么“改好一个bug,引发其它bug”这样的事情虽非常可能会见产生。永远不亮堂刚的更动会发出什么副作用,很可能会见引发一多元的相关反应

  那么,有无起点子于无修改代码的气象下,就能够满足新要求呢?通过长代码,而非是修改代码的章程,来深受window.onload函数添加新的效用,代码如下:

Function.prototype.after = function( afterfn ){
    var __self = this;
    return function(){
        var ret = __self.apply( this, arguments );
        afterfn.apply( this, arguments );
        return ret;
    }
};
window.onload = ( window.onload || function(){} ).after(function(){
    console.log( document.getElementsByTagName( '*' ).length );
});

  通过动态装饰函数的艺术,完全不用理会从前window.onload函数的其中贯彻,无论她的贯彻优雅或丑陋。就算当维护者,拿到之是平份混淆压缩了的代码也未曾提到。只要其过去是只安定运转的函数,那么之后吧未会见因咱们的新增需求使发错误。新增的代码和原有的代码可以井水不犯河水

  现在引出开放——封闭原则的思:当用变更一个次的作用要受此次增加新成效的上,可以采用增多代码的不二法门,但是非容许改动程序的源代码

  过多之原则分支语句是导致程序违反开放——封闭原则的一个科普原因。每当要增加一个新的if语句时,都如被迫转移原来函数。把if换成switch-case是从来不就此底,这是一样种植换汤不换药的做法。实际上,每当看到同样坏片的if或者swtich-case语句子时,第一时间就应当考虑,能否采用对象的多态性来重构它们

  以目标的多态性来受程序遵守开放——封闭原则,是一个常用之技巧。下面先提供相同截不符合开放——封闭原则的代码。每当增加一栽新的动物经常,都用改makeSound函数的内部贯彻:

var makeSound = function( animal ){
    if ( animal instanceof Duck ){
        console.log( '嘎嘎嘎' );
    }else if ( animal instanceof Chicken ){
        console.log( '咯咯咯' );
    }
};

var Duck = function(){};
var Chicken = function(){};
makeSound( new Duck() ); // 输出:嘎嘎嘎
makeSound( new Chicken() ); // 输出:咯咯咯

  动物世界里添一单独狗之后,makeSound函数必须转成为:

var makeSound = function( animal ){
    if ( animal instanceof Duck ){
        console.log( '嘎嘎嘎' );
    }else if ( animal instanceof Chicken ){
        console.log( '咯咯咯' );
    }else if ( animal instanceof Dog ){ // 增加跟狗叫声相关的代码
        console.log('汪汪汪' );
    }
};
var Dog = function(){};
makeSound( new Dog() ); // 增加一只狗

  以多态的想想,把程序中未转移的一对隔断出(动物都见面吃),然后把可变的组成部分包装起来(不同档次的动物来不同的喊叫声),这样一来程序就算有所了而扩展性。想吃同样就狗发出叫声时,只待多一段代码即可,而非用失去改变原来的makeSound函数:

var makeSound = function( animal ){
    animal.sound();
};
var Duck = function(){};
Duck.prototype.sound = function(){
    console.log( '嘎嘎嘎' );
};
var Chicken = function(){};
Chicken.prototype.sound = function(){
    console.log( '咯咯咯' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯
/********* 增加动物狗,不用改动原有的makeSound 函数 ****************/
var Dog = function(){};
Dog.prototype.sound = function(){
    console.log( '汪汪汪' );
};
makeSound( new Dog() ); // 汪汪汪

  遵守开放——封闭原则的规律,最鲜明的尽管是寻觅有程序中即将发生变化的地方,然后把转变封装起来。通过包变化的法子,可以把系统遭到泰不转移的局部及易于变化的片隔断开来。在系的演化过程遭到,只需要替换那些易变化之一对,如果这些有些是一度给打包好的,那么替换起来也针锋相对好。而变化有外的哪怕是稳定之有些。在系的嬗变过程遭到,稳定的有的是勿待改之

  由于每种动物的喊叫声都不可同日而语,所以动物具体怎么为是可变的,于是把动物具体怎么吃的逻辑从makeSound函数中分离出来。而动物都见面叫这是不变换的,makeSound函数里的贯彻逻辑只及动物都见面为有关,这样一来,makeSound就成为了一个平稳与查封的函数。除了采取对象的多态性之外,还发出其它办法得以拉编写遵守开放——封闭原则的代码

【放置联系】

  放置联系(hook)也是分离变化的一致栽艺术。在程序来或发生变化的地方停放一个关联,挂钩的回结果决定了次的产同样步走向。这样一来,原本的代码执行路径上就是应运而生了一个分叉路口,程序未来底履方向给先行埋下又可能性。

  由于子类的数是任界定的,总会有一部分“个性化”的子类迫使不得不失去改变都封装好之算法骨架。于是可以当父类中的某容易变之地方放联系,挂钩的返结果由于具体子类决定。这样一来,程序即使拥有了变化的恐怕

【使用回调函数】

  以javascript中,函数可以看做参数传递给另外一个函数,这是高阶函数的意义有。在这种情况下,通常会将此函数称为回调函数。在javascript版本的设计模式中,策略模式以及指令模式相当于还足以用回调函数轻松实现

  回调函数是如出一辙种植异常的沟通。可以将部分便于变动之逻辑封装在回调函数里,然后把回调函数当作参数传入一个安乐和查封的函数中。当回调函数被实践之时段,程序即使可以以回调函数的里逻辑不同,而起不同之结果

  比如,通过ajax异步请求用户信息后要做一些工作,请求用户信息的进程是勿变换的,而获得到用户信息之后如果做什么工作,则是唯恐转变的:

var getUserInfo = function( callback ){
    $.ajax( 'http:// xxx.com/getUserInfo', callback );
};
getUserInfo( function( data ){
    console.log( data.userName );
});
getUserInfo( function( data ){
    console.log( data.userId );
});

  另外一个例子是关于Array.prototype.map的。在无支持Array.prototype.map的浏览器中,可以概括地效实现一个map函数

  arrayMap函数的企图是拿一个数组“映射”为另外一个数组。映射的步调是无变换的,而映射的条条框框是可变的,于是将当下有规则放在回调函数中,传入arrayMap函数:

var arrayMap = function( ary, callback ){
    var i = 0,
    length = ary.length,
    value,
    ret = [];
    for ( ; i < length; i++ ){
        value = callback( i, ary[ i ] );
        ret.push( value );
    }
    return ret;
}
var a = arrayMap( [ 1, 2, 3 ], function( i, n ){
    return n * 2;
});
var b = arrayMap( [ 1, 2, 3 ], function( i, n ){
    return n * 3;
});

console.log( a ); // 输出:[ 2, 4, 6 ]
console.log( b ); // 输出:[ 3, 6, 9 ]

  有同样种植说法是,设计模式就是吃开的好之宏图获个名。几乎有的设计模式都是信守开放——封闭原则的。不管是现实的各种设计模式,还是再次抽象的面向对象设计条件,比如单一任务规范、最少知识标准化、依赖倒置原则等,都是以吃程序遵守开放——封闭原则而起的。可以如此说,开放——封闭原则是编写一个好程序的目标,其他计划标准都是高达这目标的经过

【发布——订阅模式】

  宣布——订阅模式用来下滑多只目标之间的依赖关系,它可以取代对象中硬编码的关照机制,一个目标无须再行显式地调用另外一个对象的有接口。当有新的订阅者出现不时,发布者的代码不待展开任何改动;同样当发布者需要改变时,也非会见潜移默化至事先的订阅者

【模板方法模式】

  模板方法模式是一模一样栽典型的通过包装变化来增进系统扩展性的设计模式。在一个施用了模版方法模式之主次中,子类的章程种类和实践顺序都是匪变换的,所以管当时有的逻辑抽出来放到父类的模板方法中;而子类的计具体怎么落实则是可变的,于是将当下一部分转的逻辑封装到子类中。通过加新的子类,便可知叫系统增加新的效益,并不需要改动抽象父类以及其他的子类,这为是副开放——封闭原则的

【策略模式】

  策略模式和模板方法模式是同一对准竞争者。在大部分状况下,它们可以彼此替换下。模板方法模式基于继承的构思,而策略模式则注重于整合和嘱托。策略模式将各种算法都封装成单独的策略类,这些策略类可以让换成使用。策略和运政策的客户代码可以分别独立进行改动要互不影响。增加一个新的策略类也十分方便,完全无用修改前的代码

【代理模式】

  用预加载图片举例,现在曾经生一个于图片设置src的函数myImage,想啊它长图预加载功能时,一种做法是反myImage函数内部的代码,更好之做法是供一个摄函数proxyMyImage,代理函数负责图片预加载,在图纸预加载完成后,再以请求转交给原的myImage函数,myImage在是进程中不需要其他改变。预加载图片的机能与于图片设置src的机能为隔离在片独函数里,它们可独立改变而互不影响。myImage不知晓代理的存在,它好继续留意于自己之任务——给图片设置src

【职责链模式】

  将一个壮烈的订单函数分别拆成了500首订单、200首订单和日常订单的3单函数。这3单函数通过职责链连接于一起,客户的恳求会当当下长长的链子中依次传递:

var order500yuan = new Chain(function( orderType, pay, stock ){
// 具体代码略
});

var order200yuan = new Chain(function( orderType, pay, stock ){
// 具体代码略
});

var orderNormal = new Chain(function( orderType, pay, stock ){
// 具体代码略
});

order500yuan.setNextSuccessor( order200yuan ).setNextSuccessor( orderNormal ); 
order500yuan.passRequest( 1, true, 10 );    // 500 元定金预购,得到 100 优惠券

  可以看来,当多一个初路的订单函数时,不欲改原来的订单函数代码,只需要在链被增一个初的节点

  在职责链模式代码中,开放——封闭原则要求只能通过长源代码的方法扩大程序的功力,而非同意修改源代码。那往职责链中增一个新的100头订单函数节点时,不为不能不变更设置链条的代码吗?代码如下:

order500yuan.setNextSuccessor(order200yuan).setNextSuccessor(orderNormal);

  变为:

order500yuan.setNextSuccessor(order200yuan).setNextSuccessor(order100yuan).setNextSuccessor(orderNormal);

  实际上,让程序保持了封闭是无易于就的。就算是技术及举行得,也待花太多之时及精力。而且给程序符合开放——封闭原则的代价是引入更多的抽象层次,更多之虚幻出或会见增大代码的复杂度。更何况,有局部代码是无论如何也未能够完全封闭的,总会设有部分无法对那个封的扭转

  作为程序员,可以做到的来下面两点

  1、挑选有极端易出转移之地方,然后构造抽象来封闭这些变迁

  2、在不可避免发生修改的早晚,尽量修改那些相对容易改的地方。拿一个开源库来说,修改其提供的布局文件,总比修改它的源代码来得简单

 

相关文章

网站地图xml地图