5.12.1 封装变化
封装变化是很多行为模式的主题。当一个程序的某个方面的特征经常发生改变时,这些模式就定义一个封装这个方面的对象。这样当该程序的其它部分依赖于这个方面时,它们都可以与此对象协作。这些模式通常定义一个抽象类来描述这些封装变化的对象,并且通常该模式依据这个对象来命名。例如:
- 一个Strategy对象封装一个算法(Strategy(5.9))
- 一个State对象封装一个与状态相关的行为(State(5.8))
- 一个Mediator对象封装对象间的协议(Mediator(5.5))
- 一个Iterator对象封装访问和遍历一个聚集对象中的各个构件的方法(Iterator(5.4))
这些模式描述了程序中很可能会改变的方面。大多数模式有两种对象:封装该方面特征的新对象,和使用这些新的对象的已有对象。如果不使用这些模式的话,通常这些新对象的功能就会变成这些已有对象的难以分割的一部分。例如,一个Strategy的代码可能会被嵌入到其Context类中,而一个State的代码可能会在该状态的Context类中直接实现。
但不是所有的对象行为模式都象这样分割功能。例如,Chain of Responsibility(5.1)可以处理任意数目的对象(即一个链),而所有这些对象可能已经存在于系统中了。
职责链说明了行为模式间的另一个不同点:并非所有的行为模式都定义类之间的静态通信关系。职责链提供在数目可变的对象间进行通信的机制。其他模式涉及到一些作为参数传递的对象。
5.12.2 对象作为参数
一些模式引入总是被用作参数的对象。例如Visitor(5.11)。一个Visitor对象是一个多态的Accept操作的参数,这个操作作用于该Visitor对象访问的对象。虽然以前通常代替Visitor模式的方法是将Visitor代码分布在一些对象结构的类中,但Visitor从来都不是它所访问的对象的一部分。
其他模式定义一些可作为令牌到处传递的对象,这些对象将在稍后被调用。Command(5.2)和Memento(5.6)都属于这一类。在Command中,令牌代表一个请求;而在Memento中,它代表在一个对象在某个特定时刻的内部状态。在这两种情况下,令牌都可以有一个复杂的内部表示,但客户并不会意识到这一点。但这里还有一些区别:在Command模式中多态很重要,因为执行Command对象是一个多态的操作。相反,Memento接口非常小,以至于备忘录只能作为一个值传递。因此它很可能根本不给它的客户提供任何多态操作。
5.12.3 通信应该被封装还是被分布
Mediator(5.5)和Observer(5.7)是相互竞争的模式。它们之间的差别是,Observer通过引入Observer和Subject对象来分布通信,而Mediator对象则封装了其它对象间的通信。
在Observer模式中,不存在封装一个约束的单个对象,而必须是由Observer和Subject相互协作来维护这个约束。通信模式由观察和目标连接的方式决定:一个目标通常有多个观察者,并且有时一个目标的观察者也是另一个观察者的目标。Mediator 模式的目的是集中而不是分布。它将维护一个约束的职责直接放在一个中介者中。
SmallTalk中的Observer可以用消息进行参数化以访问Subject的状态,因此与在C++中的Observer相比,它们具有更大的可复用性。这使得 SmallTalk中的Observer比Mediator更具吸引力。因此一个SmallTalk程序员通常会使用Observer而一个C++程序员则会使用Mediator。