zoukankan      html  css  js  c++  java
  • javaScript设计模式简记(3)-行为型设计模式

    1.模板方法模式

    模板方法模式(Template Method):父类中定义-组操作算法骨架,而将一些实现步骤延迟到子类中,使得子类可以不改变父类的算法结构的同时可重新定义算法中某些实现步骤。

    比如我们生活中用蛋糕模具做蛋糕,做出的蛋糕是外形相同的,因为他们都用的同一个模具,这是最基本的一一个蛋糕。当然我们看到商店里卖的蛋糕五花八门,有的涂层奶油,有的抹上巧克力,有的浸入果汁等,这都是对蛋糕的二次加工,也就是说顾客对蛋糕有不同的需求,所以为了满足更多顾客需求,烤制出蛋糕后,我们还要对他们再添加点美味的作料,让他们更美味而满足每个顾客的需求。所以说我们需求解决方案中提到的基本提示框应该就是我们要抽象出来的,因为它是最简单的一个提示框,其他提示框都比这个提示框要多一-些功能,也就是说我们要对这个添加一些‘佐料’让其满足用户的需求。比如标题提示框多了一个标题组件,取消按钮提示框多了一个取消按钮组件,但是首先要实现最基础的提示框。

     

     

     使用

    模板方法的核心在于对方法的重用,它将核心方法封装在基类中,让子类继承基类的方法,实现基类方法的共享,达到方法共用。当然这种设计模式也将导致基类控制子类必须遵守某些法则。这是一种行为的约束。当然为了让行为的约束更可靠,基类中封装的方法通常是不变的算法,或者具有稳定的调用方式。子类继承的方法亦是可以扩展的,这就要求对基类继承的方法进行重写。当然为了更好地实践,通常要控制这种拓展,这样才能让基类对子类有更稳健的束缚力。然而子类对自身私有行为的拓展还是很有必要的。

    2.观察者模式

     观察者模式(Observer): 又被称作发布-订阅者模式或消息机制,定义了-一种依赖关系,解决了主体对象与观察者之间功能的耦合。

    简单实现

    观察者模式最主要的作用是解决类或对象之间的耦合,解耦两个相互依赖的对象,使其依赖于观察者的消息机制。这样对于任意一一个订阅者对象来说,其他订阅者对象的改变不会影响到自身。对于每一个订阅者来说,其自身既可以是消息的发出者也可以是消息的执行者,这都依赖于调用观察者对象的三种方法(订阅消息,注销消息,发布消息)中的哪一种。团队开发中,尤其是大型项目的模块化开发中,一位工程师很难做到熟知项目中的每个模块,此时为完成一-个涉及多模块调用的需求,观察者模式的优势就显而易见了,模块间的信息传递不必要相互引用其他模块,只需要通过观察者模式注册或者发布消息即可。通过观察者模式,工程师间对功能的开发只需要按照给定的消息格式开发各自功能即可,而不必去担忧他人的模块。

    3.状态模式

    状态模式(State): 当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。

    小例子

     状态模式既是解决程序中臃肿的分支判断语句问题,将每个分支转化为-一种状态独立出来,方便每种状态的管理又不至于每次执行时遍历所有分支。在程序中到底产出哪种行为结果,决定于选择哪种状态,而选择何种状态又是在程序运行时决定的。当然状态模式最终的目的即是简化分支判断流程。

    4.策略模式

    策略模式(Strategy): 将定义的一组算法封装起来,使其相互之间可以替换。封装的算法具有一定独立性,不会随客户端变化而变化。

    策略模式最主要的特色是创建一系列策略算法,每组算法处理的业务都是相同的,只是处理的过程或者处理的结果不一样,所以它们又是可以相互替换的,这样就解决了算法与使用者之间的耦合。在测试层面上讲,由于每组算法相互之间的独立性,该模式更方便于对每组算法进行单元测试,保证算法的质量。对于策略模式的优点可以归纳为3点,第一,策略模式封装了一组代码簇,并且封装的代码相互之间独立,便于对算法的重复引用,提高了算法的复用率。第二,策略模式与继承相比,在类的继承中继承的方法是被封装在类中,因此当需求很多算法时,就不得不创建出多种类,这样会导致算法与算法的使用者耦合在一起, 不利于算法的独立演化,并且在类的外部改变类的算法难度也是极大的。第三,同状态模式一样, 策略模式也是一种优化分支判断语句的模式,采用策略模式对算法封装使得算法更利于维护。当然策略模式也有其自身的缺点。由于选择哪种算法的决定权在用户,所以对用户来说就必须了解每种算法的实现。这就增加了用户对策略对象的使用成本。其次,由于每种算法间相互独立,这样对于一些复杂的算法处理相同逻辑的部分无法实现共享,这就会造成一些资源的浪费。可以通过享元模式来解决。对于分支语句的优化,有3种模式,分别为工厂方法模式,状态模式与策略模式。对于工厂方法模式来说,它是一种创建型模式,他的最终目的是创建对象。而状态模式与策略模式都是行为型模式,不过在状态模式中,其核心是对状态的控制来决定表现行为,所以状态之间通常是不能相互替代的,否则将产生不同的行为结果。而策略模式核心是算法,由于每种算法要处理的业务逻辑相同,因此他们可以相互替换,当然策略模式并不关心使用者环境,因为同一种策略模式最终产出的结果是一定的。

    5.职责链模式

    职责链模式(Chain of Responsibility):解决请求的发送者与请求的接受者之间的耦合,通过职责链上的多个对象对分解请求流程,实现请求在多个对象之间的传递,直到最后一个对象完成请求的处理。

    客户端发出一个请求,链上的对象都有机会来处理这一请求,而客户端不需要知道谁是具体的处理对象。这样就实现了请求者和接受者之间的解耦,并且在客户端可以实现动态的组合职责链。使编程更有灵活性。

    定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。其过程实际上是一个递归调用。

    要点主要是:

      1、有多个对象共同对一个任务进行处理。

      2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。

      3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个任务。也可以在此对象上结束任务的处理,并结束任务。

      3、客户端负责组装链式结构,但是客户端不需要关心最终是谁来处理了任务。

    6.命令模式

    命令模式(Command):将请求与实现解耦并封装成独立对象,从而使不同的请求对客户端的实现参数化。

    命令模式是将执行的命令封装,解决命令的发起者与命令的执行者之间的耦合。每一条命令实质上是一个操作。命令的使用者不必要了解命令的执行者(命令对象)的命令接口是如何实现的、命令是如何接受的、命令是如何执行的。所有的命令都被存储在命令对象中。

    命令模式的优点自然是解决命令使用者之间的耦合。新的命令很容易加入到命令系统中,供使用者使用。命令的使用具有一致性,多数的命令在一定程度上是简化操作方法的使用的。

    命令模式是对一-些操作的封装, 这就造成每执行一次操作都要调用一次命令对象,增加了系统的复杂度。

    7.访问者模式

    访问者模式(Visitor); 针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法。

     

    访问者模式解决数据与数据的操作方法之间的耦合,将数据的操作方法独立于数据,使其可以自由化演变。因此访问者更适合于那些数据稳定,但是数据的操作方法易变的环境下。因此当操作环境改变时,可以自由修改操作方法以适应操作环境,而不用修改原数据,实现操作方法的拓展。同时对于同一个数据,它可以被多个访问对象所访问,这极大增加了操作数据的灵活性。

    访问者模式的优点
    a、符合单一职责原则:凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
    b、扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展。

    访问者模式的适用场景
    a、假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
    b、假如一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。

    8.中介者模式

    中介者模式(Mediator):通过中介者对象封装一系列对象之 间的交互,使对象之间不再相互引用,降低他们之间的耦合。有时中介者对象也可改变对象之间的交互。

    同观察者模式一样,中介者模式的主要业务也是通过模块间或者对象间的复杂通信,来解决模块间或对象间的耦合。对于中介者对象的本质是分装多个对象的交互,并且这些对象的交互一般都是在中介者内部实现的。与外观模式的封装特性相比,中介者模式对多个对象交互地封装,且这些对象一般处于同一层面上,并且封装的交互在中介者内部,而外观模式封装的目的是为了提供更简单的易用接口,而不会添加其他功能。与观察者模式相比,虽然两种模式都是通过消息传递实现对象间或模块间的解耦。观察者模式中的订阅者是双向的,既可以是消息的发布者,也可以是消息的订阅者。而在中介者模式中,订阅者是单向的,只能是消息的订阅者。而消息统一由中介者对象发布, 所有的订阅者对象间接地被中介者管理。

    9.备忘录模式

    备忘录模式(Memento):在不破坏对象的封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后对象使用或者对象恢复到以前的某个状态。

    备忘录模式最主要的任务是对现有的数据或状态做缓存,为将来某个时刻使用或恢复做准备。在JavaScript编程中,备忘录模式常常运用于对数据的缓存备份,浏览器端获取的数据往往是从服务器端请求获取到的,而请求流程往往是以时间与流量为代价的。因此对重复性数据反复请求不仅增加了服务器端的压力,而且造成浏览器端对请求数据的等待进而影响用户体验。在备忘录模式中,数据常常存储在备忘录对象的缓存器中,这样对于数据的读取必定要通过调用备忘录提供的方法,因此备忘录对象也是对数据缓存器的一次保护性封装,防止外界的直接访问,方便数据的管理,规范化外界对象对数据的使用。一旦备忘录对象发现请求的数据或状态在缓存器中已存在,将直接从缓存器中读取,从而降低对数据的获取成本。当数据量过大时,会严重占用系统提供的资源,这会极大降低系统性能。此时对缓存器的缓存策略优化是很有必要的,复用率低的数据缓存下来是不值得的。因此资源空间的限制是影响备忘录模式应用的一大障碍。不过随着硬件水平的提高以及浏览器的不断优化,相信资源空间的限制在不久的将来也会得到改善。

    10.迭代器模式

    迭代器模式(Iterator):在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素。

    典型例子: $.each()

    简单实现

    var each = function( ary, callback ){
        for ( var i = 0, l = ary.length; i < l; i++ ){
        callback.call( ary[i], i, ary[ i ] ); // 把下标和元素当作参数传给callback函数
        }
    };
    each( [ 1, 2, 3 ], function( i, n ){
        alert ( [ i, n ] );
    });

    分为内部迭代器和外部迭代器

      a.内部迭代器

      内部迭代器的内部已经定义好了迭代规则,它完全接手整个迭代过程,外部只需要一次初始调用。如each函数就是一个内部迭代器

      b.外部迭代器

      外部迭代器必须显式地请求迭代下一个元素。外部迭代器增加了一些调用的复杂度,但相对也增强了迭代器的灵活性,我们可以手工控制迭代的过程或者顺序。

    // 外部迭代器
    var
    Iterator = function( obj ){ //初始化索引 var current = 0; //下一个 var next = function(){ current += 1; }; //如果当前的索引大于或者等于参数的个数,则已经是最后一个 var isDone = function(){ return current >= obj.length; }; //获取当前迭代对象 var getCurrItem = function(){ return obj[ current ]; }; //返回 return { next: next, isDone: isDone, getCurrItem: getCurrItem } };

    通过迭代器我们可以顺序地访问一个聚合对象中的每一个元素。 在开发中,迭代器极大简化了代码中的循环语句,使代码结构清晰紧凑,然而这些简化了的循环语句实质上隐形地移到了迭代器中。当然用迭代器去处理-一个对象时,我们只需提供处理的方法,而不必去关心对象的内部结构,这也解决了对象的使用者与对象内部结构之间的耦合。当然迭代器的存在也为我们提供了操作对象的一个统一接口。

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。

    11.解释器模式

    解释器模式(Interpreter): 对于一种语言,给出其文法表示形式,并定义一种解释器,通过使用这种解释器来解释语言中定义的句子。

     例子:获取点击元素的Xpath

    详见这篇博文

  • 相关阅读:
    程序是怎样跑起来的 第三章
    C#4.5-4.7学习总结
    第二周学习总结
    程序是如何跑起来的 第二章
    第一章读后感
    师生关系读后感
    C#学习总结
    我与计算机
    读《程序怎样跑起来》第一章有感
    读师生关系有感
  • 原文地址:https://www.cnblogs.com/LeoXnote/p/13052339.html
Copyright © 2011-2022 走看看