设计模式学习笔记(七):行为型模式

行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述

它们之间的通信模式。这些模式刻画了在运行时难以跟踪的复杂的控制流。它们将你的注意

力从控制流转移到对象间的联系方式上。

    行为型模式的三个典型特点 :

封装变化

对象作为参数

对发送者和接收者解耦

 

Chain of Responsibility

意图 :为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求 。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。

动机: 解除请求的发送者和接收者之间耦合,在对象间传递待处理的请求。

适用性: 用于请求的跨层传递,解除请求发送者和请求的最终处理者之间的耦合。统一地处理客户请求。常用于窗口系统,处理鼠标或键盘事件,典型应用: wxWidget 的事件系统。

结构: 客户请求一般采用 Command 封装 ,使易于传递。一般不同对象采用统一的接口来处理请求。如果请求处理者对象存放在列表中,一般要求使用继承实现。

优点: 易于请求的跨层传递;解除对象耦合( 封装请求的真实处理者) ;统一请求处理( 封装请求的变化)

组合模式: 经常采用 Command 来封装不同类型的请求.

 

Command

意图 将一个请求封装为一个对象 ,从而可用不同的请求对客户进行参数化( 传递请求) ;对请求排队或记录请求日志,以及支持可取消的操作。

动机: 封装请求的类型;让请求具有对象的特性( 具有状态的实体 ), 这样就可以传递、保存 或者采用不同的方式来处理请求对象。

结构: 用继承来封装请求的类型;除了不一样的构造和初始化函数外,提供一致的核心接口。

优点: 让请求具有对象的特性,使客户能够采用不同的方式来处理请求对象,比如可以解除对象构造和对象使用的耦合,即实体解耦和时间解耦。

用途: 经常用于数据库事务操作,设备控制,多线程核心 (Active Object) 以及 GUI do/undo 管理等。或者用于消除过多的条件分派。

组合模式: 经常用于 Chain of Responsibility 中的请求封装;经常和 Composite 组合使用,提供统一的对待 Command 的途径,封装“一对多 的关系。

 

Iterator

意图 :提供一种方法顺序访问一个聚合对象中各个元素 , 而又不需暴露该对象的内部表示。

动机: 封装对对象的访问规则或者算法。本质:提供一致的遍历接口

适用性: 适用于为多个不同聚合类提供一致的遍历接口。

结构:抽象迭代器提供类似 hasNext(), Next(), Remove() 等接口,并由具体聚合类通过 createIterator() 创建具体的迭代器。

优点: 封装聚合类内部实现,提供一致对外接口

 

Interpreter

意图 :给定一个语言 , 定义它的文法的一种表示,并定义一个解释器 , 该解释器使用自身定义表示来解释语言中的句子。

动机: 采用不同的对象来表示不同的文法 ,使文法易于组合使用。提供一种可选择的方式,将易变的组合逻辑推给客户代码。

结构:将每一个语法规则表示成一个类 ,方便于实现语言。

适用性:方便实现简单语言的解释器( 常用 yacc lex 工具来编写语言的解释器原型)

 

Mediator

意图 :用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可独立地改变它们之间的交互。

动机: 封装多个对象间的交互关系,解除耦合。

适用性: 适用于多个对象交互关系复杂且易变的情况。常用于协调GUI 组件

结构: 提供一个幕后类来统一管理不同对象间的交互关系。

优点: 封装多个对象间的交互关系,使客户更加容易编程。

 

Memento

意图 :在不破坏封装性的前提下,捕获一个对象的内部状态 ,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。

动机: 保存对象状态,用于对象状态的回滚或重新构造。

适用性: 用于对象内部状态易变,且对象状态具有某种价值的场合。

结构: 使用简单的结构体即可完成任务。

优点: 提供保存对象的另一种选择。

缺点:存储耗时,常用语言自带的序列化 (serialization) 机制存储系统状态。

 

Observer

意图 :定义对象间的一种一对多的依赖关系 以便当一个对象的状态发生改变时 所有依赖于它的对象都得到通知并自动刷新。

动机: 封装对象间一对多的依赖关系,提供统一的管理点。

适用性: 所有具有一对多依赖关系且需要传递状态信息的对象管理。

结构: 使用双抽象结构( 主题和观察者 ), 一个抽象管理主题状态的通知行为 ( 简化主题派生类的行为), 一个抽象用于封装不同的状态观察者

优点: 在具有多个观察者时,可简化状态通知部分的 Hard-coding ,并且易于扩展。

变化: 在状态比较复杂的情况下, 一般采用某种约定的参数来提示观察者状态发生了什么样的变化,简化对象更新过程。

 

State

意图 :允许一个对象在其内部状态改变 时改变它的行为( 外部行为) 。对象看起来似乎修改了它所属的类。

动机: 分离状态机的逻辑和动作;或者是分离状态和行为( 动作)

结构: state 定义所用具体状态的共同接口 ( 事件接口) ;任何具体状态实现该相同接口 Context 拥有所有状态对象。根据不同事件, context 在不同状态对象中切换,从而改变自身行为。

优点:避免用户直接和状态交互;去除掉大量的条件语句;使系统更加易于扩展和维护。

 

变化:1 )一般来讲,当状态改变是固定的,状态转换逻辑适合放在 Context 中;当转换更动态的时候,通常将状态转换逻辑放在 State 中,但这会使状态类之间产生依赖。总之,该决策决定了究竟哪个类是对修改封闭的 context state 2 )如有多个 Context ,则可考虑共享所有的状态类。

 

Strategy

意图 :定义一系列的算法 把它们一个个封装起来 , 并且使它们可相互替换。该模式使得算法的变化可独立于使用它的客户。

动机: 封装不同的算法 。定制一组可以互换的算法族。

适用性: 同一个问题存在多种不同的解决方案。

结构: 为了满足算法之间的互换性,必须使用继承,并且遵循 Liskov 原则。

优点: 封装算法的变化。

组合模式: 经常在使用算法的基类 Context 中使用 Template Method 如果 Context 的派生类中要求所使用的算法动态改变,还常常把 Factory Method 内嵌到派生类中来创建不同的算法类。

区别:策略模式和状态模式具有相同类图。策略模式是围绕可互换的算法来创建业务的,由 Client 自行决定具体策略。状态模式则通过改变对象内部状态帮助对象控制自己的行为。

 

Template Method

意图 :定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

动机: 消除子类中的重复代码,简化子类代码。

适用性: 当各个子类中,混杂着不变和可变的行为时,就可以使用该模式。将不变的行为放入父类中,子类只需定制可变的行为。这里不变还包括行为的执行顺序。

结构: 必须使用继承关系。

优点: 消除子类的重复行为。

组合模式: 经常和 Factory Method Strategy 一起使用。在分解不变和可变行为时,还常可借助组合方法 (Compose Method) Collecting Parameter 模式。

 

Visitor

意图 :表示一个作用于某对象结构中的各元素的操作 。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

动机: 在不改变原类( 一般是特定的数据结构) 的情况下, 增加新的功能接口。

适用性: 原有的类结构不能或者不容易改变;或者新加的功能不属于原类的职责范畴。

结构: 双重分派。增加一个 Visitor 类,并针对所有要访问的派生类增加单独的访问接口( Visitor ) 。本质上, Visitor 模式中的两次分派形成一个功能矩阵 Visitor 的接口名字和其接受的派生类类型分别是功能矩阵的两个变化轴。

优点: 使用 Visitor 模式,使程序中的数据结构( 原类) 独立于它的用途。

用途: 一般如果应用程序中存在有需要以多种不同方式进行解释的数据结构 ,就可以使用 Visitor 模式。比如使用 Visitor 模式来遍历所有的配置数据来初始化不同的应用程序子系统。最常见的应用: 遍历大量的数据结构并产生不同类型的报表。

缺点:会破环组合类的封装。

 

Null Object

意图 : 提供一个没有任何行为的对象。

动机 : 消除代码中四处存在的无效对象判断

适用性 : 只要对无效对象的判断逻辑多次出现时,就有引入 Null Object 的必要。

结构 : Null Object 肯定是作为派生类的一个种类出现,并用于取代没有合适派生类可用的情形。比如,对象放在 Map 中,查找可能无效。

优点 : 消除对无效对象的判断逻辑,提供系统的可靠性。

 

待续.....

 

你可能感兴趣的:(软件工程与开发工具)