UML软件工程组织

Pattern Tips 之五
作者:温昱(选自松耦合空间)
Builder,Visitor,Observer,Mediator。它们都是Behavioral Patterns(在此认为Creationall Patterns是特殊的Behavioral Patterns)。

更重要的是,它们都是比较“难”的模式,它们的共性是:模式本身就有多个Role协作──比如Builder/Director,Visitor/Element,Observer/Subject,Mediator/Colleague。

----------------------------------Builder----------------------------

●Tip 1:关键字。Complex,Assemble。

●Tip 2:图。



可以看到,Director只控“宏观过程”,具体工作委托(delegate)Builder去做。

●Tip 3:实现和使用。

“Architect或Achitecture工程师”负责写Director和Builder。而Product和Part的实例化(以及把Part组装的Product),是Builder的首要职责。

“Application工程师”负责写Client,Director和Builder一般是由该Client实例化的。Director将具体调用哪个Builder,由Client告诉Director。

MFC中,App/CCtrlView/CListView/CListCtrl/Column and Item分别是Director/Abstract Builer/Concrete Builer/Product/Part。

●Tip 4:优点。Finer control over the assembling process。

控制的“粒度”比较精细体现在Director和Builder的分离上(想一下Abstract Factory是“construct products in one shot”的),Builder的职责是Create a part and assemble it to product,Director的职责是Control builder's assembling process。

可以通过Director的不同写法来满足不同的需求:可以是“数据驱动”的,比如战略游戏的Director可以去读地图文件生成地图,文档格式转换程序的Director可以去读“源格式文件”生成“目标格式文件”;可以是“用户驱动”的,比如Word或Photoshop这些编辑软件的Director是个大大的消息循环,根据用户的操作来具体构造文档;当然也可以对assembling process硬编码,如书中附带的例子,

Maze* MazeGame::CreateMaze( Mazebuilder & builder )
{
  builder.BuildMaze();  //create the Product

  builder.BuildRoom(1);  //create 3 Parts of Product and assemble them to the Product
  builder.BuildRoom(2);
  builder.BuildDoor(1, 2);

  return builder.GetMaze();
}
●Tip 5:支持变化。

Director可以通过调用Builder来达到“细粒度”的控制,而且它是通过AbstractBuilder这个非常稳定的Interface建立协作的,Director和ConcreteBuilder之间不存在直接的耦合关系。所以,Director和ConcreteBuilder都相当“自由”。图中黄色的Director是新写的,以支持新的Assemble策略,令“Architect或Achitecture工程师”高兴的是,没有对Builder及其子类做任何改动。

----------------------------------Visitor----------------------------

●Tip 1:关键字。New Operation。

●Tip 2:图。



可以看到,为了达到“将Aalgorithm从Data分离出来”的目的,代价是1.5 个对象:新增Visitor,Element增加Accept()操作。

●Tip 3:实现和使用。

我认为当CWnd::SubclassWindow()或CWnd::SubclassDlgItem()时,CWnd就是window obj的Visitor。

●Tip 4:优点。算法集中,易于维护。Related behavior isn't spread over the classes defining the object structure; it's localized in a visitor。

●Tip 5:支持变化。Visitor makes adding new operations easy。图中的黄色Class就是假想后来扩充的。

●Tip 6:局限性。

只能用于 The classes defining the object structure rarely change, but you often want to define new operations over the structure。 因为 Most of these operations will need to treat nodes that represent assignment statements differently from nodes that represent variables or arithmetic expressions。所以 Adding new ConcreteElement classes is hard。所以 If the object structure classes change often, then it's probably better to define the operations in those classes。

Visitor and Element之间是紧耦合。Breaking encapsulation. Visitor's approach assumes that the ConcreteElement interface is powerful enough to let visitors do their job. As a result, the pattern often forces you to provide public operations that access an element's internal state, which may compromise its encapsulation.

----------------------------------Ovserver----------------------------

●Tip 1:关键字。Notify,Dependency。

●Tip 2:图。



可以看到,首先,concreteListener调用concreteBroadcaster.AddListener( this )“订阅”消息;然后某时,concreteBroadcaster调用Broadcast()“发布”消息,已订阅消息的concreteListener的ListenToMessage()被调用执行。

●Tip 3:实现和使用。

When the dependency relationship between Broadcasters and Listeners is particularly complex, an object that maintains these relationships might be required. We call such an object a ChangeManager. ChangeManager is an instance of the Mediator pattern.

MFC中,CView就是CDocument的Observer,CListView就是CListCtrl的Observer。

值得说明的是,经典的Mediator模式中,各Colleague是完全“平等”的,任何一个Colleague的变化都可能引起其它Colleague相应改变;但这里的Colleague是由Broadcaster和Listener充当,它们是“不平等”的──Broadcaster总是发起者,Listener总是响应者。哈哈,以此观点,Facade也是一种Mediator了。

下图中,ChangeManager会有一个broadcaster_listener_map数据结构,它可以很复杂,Broadcaster::AddListener()和ChangeManager::Register()的参数都要相应复杂,比如从“订阅某Broadcaster的消息”变成“订阅某Broadcaster的某类消息”或“订阅所有某类消息”。



Observer pattern appears in Smalltalk Model/View/Controller (MVC)。。。



●Tip 4:支持变化。The Observer pattern lets you vary subjects and observers independently. All a subject knows is that it has a list of observers, each conforming to the simple interface of the abstract Observer class。注意图中和Framework内的对象相关的依赖都是良性依赖,被标成绿色,正是这些良性依赖使得Application中的Changeable性高的对象能够比较自由地变化。

●Tip 5:支持框架。相当于一个消息平台,图中已标出。

----------------------------------Mediator----------------------------

●Tip 1:关键字。Collective Behavior。

●Tip 2:图。



可以看到,多个Colleague变化时,都向Mediator报告;Mediator会根据具体哪个Colleague的obj发生了变化,调用相关Colleague的相关操作。

●Tip 3:实现和使用。Colleague passes a reference to itself as an argument to ColleagueChanged() to let the Mediator identify the Colleague that changed。

MFC中的Dialog是典型的Mediator,其所有control都向它报告消息。

●Tip 4:优点。It centralizes control. That can help clarify how objects interact in a system. The Mediator pattern trades complexity of interaction for complexity in the mediator.Colleagues send and receive requests from a Mediator object. The mediator implements the cooperative behavior by routing requests between the appropriate colleague(s).

●Tip 5:支持变化。It decouples colleagues. A mediator promotes loose coupling between colleagues. You can vary and reuse Colleague and Mediator classes independently。可以改Mediator::ColleagueChanged()的具体实现,以实现不同的“更新”策略;也可以增加Colleague,Mediator只需做少许相应改动。改动在图中用黄色标出。

                                      上一页     下一页

 
 

版权所有:UML软件工程组织