设计模式学习笔记(七):行为型模式
2009-09-11 13:11
330 查看
行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述
它们之间的通信模式。这些模式刻画了在运行时难以跟踪的复杂的控制流。它们将你的注意
力从控制流转移到对象间的联系方式上。
行为型模式的三个典型特点
:
封装变化
对象作为参数
对发送者和接收者解耦
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
中,查找可能无效。
优点
:
消除对无效对象的判断逻辑,提供系统的可靠性。
待续.....
它们之间的通信模式。这些模式刻画了在运行时难以跟踪的复杂的控制流。它们将你的注意
力从控制流转移到对象间的联系方式上。
行为型模式的三个典型特点
:
封装变化
对象作为参数
对发送者和接收者解耦
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
中,查找可能无效。
优点
:
消除对无效对象的判断逻辑,提供系统的可靠性。
待续.....
相关文章推荐
- 学习笔记:11种行为型设计模式简单对比
- 设计模式学习笔记——行为型(总结)
- 学习笔记:11种行为型设计模式简单对比
- C#面向对象设计模式纵横谈 学习笔记22 State模式(行为型模式)
- 学习Java 23种设计模式详解笔记之行为型模式(三)
- 设计模式学习笔记三(行为型模式)
- 设计模式学习笔记:行为型模式
- 设计模式学习笔记——建造者模式
- Java 单例设计模式 与 代码优化 学习笔记
- 【设计模式学习笔记】Adapter
- Java设计模式--单例模式学习笔记
- 【设计模式】学习笔记14:状态模式(State)
- 黑马程序员------java学习笔记之单例设计模式
- java 设计模式学习笔记十四 template模版模式
- J2SE学习笔记:设计模式之代理模式
- 【HeadFirst 设计模式学习笔记】1.策略模式
- 设计模式学习笔记---组合模式composite(Java版)
- 设计模式:学习笔记(1)——单例模式
- JAVA学习笔记-----设计模式之工厂模式
- 学习设计模式笔记(二)部分总结