标签 设计模式 下的文章

设计模式:Visitor

针对问题

当我们需要遍历一个结构并且操作这个这个结构中的对象时,可能会写出这样的代码:

这样如果我们需要修改对element元素的操作时,需要重写整个循环。同样,如果我们要修改遍历元素的算法,也需要改写这个循环。
Visitor模式分离了对象结构的“遍历”和“对象操作”,使得这两种逻辑可以分别被修改。

介绍

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

实现

Visitor模式的静态图如下:

由UML图可以看出Visitor模式有两个类层次:一个对应于接受操作元素(遍历),一个用于定义对元素操作的访问者(操作)。

下面的协作图进一步说明了Visitor模式的协作方式:

1、遍历可以由对象结构、访问者、或独立的迭代器完成。… Read the rest

设计模式:TemplateMethod

针对问题

当一个算法的大部分实现是不变的,只有一部分可变时,我们可以将算法的不变部分提取到基类中,可变部分留给派生类完成,这便是Template Method模式。

介绍

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

实现

Template Method的静态图如下:

AbstractClass中的TemplateMethod实现了算法中不变的逻辑,将可变逻辑PrimitlveOperation交给子类实现。

另一种Template Method的主要用途为hook操作:基类中提供一个默认空操作,派生类可以修改这个操作的实现,相当于在Template Method算法中“插入”了派生类的逻辑。在实现这样的hook时,基类设计者必须指明哪些是hook操作。

特点

1、Template Method模式是代码复用的一种基本技术,它提供了一种反向控制的结构:由父类调用子类的操作。… Read the rest

设计模式:Strategy

针对问题

当对象要调用某类算法时(例如排序),同一个算法可能有多种实现方式,客户程序中如果直接包含算法代码会让程序变得庞大并难以维护,这时如果要更改算法实现可能需要重写整个客户程序。Strategy模式将算法封装到独立的类型中,从而避免这些问题。

介绍

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

实现

Strategy模式的静态图如下:

其中:
Strategy类型声明算法接口,并在ConcreteStrategy类型中实现具体算法,必要时可以在算法中回调Context。
Context对象中维护strategy对象的引用,并将算法调用转发给Strategy。

在Context调用Strategy接口时可以传递算法必要的参数,或者直接传递Context本身,前者将使得Strategy和Context进一步解耦。
实现Context时可以使Strategy对象成为可选的,如果Context中有Strategy对象,则执行算法,否则继续执行。… Read the rest

设计模式:State

针对问题

假设要开发一个工作流程,流程里包括提交、审批、通过、退回几个步骤,一种设计方案如下:

设计模式:Observer

针对问题

有时一个对象状态的更改需要引发其他对象更新。最常见的情况便是在GUI编程中,对象中数据的改变需要反应到界面上。
例如一个table控件需要增加一行,传统方式是在table中创建一个新行,并为每个单元格赋值。但是这样做必然会将数据逻辑和界面逻辑耦合在一起,如果需要更新多个表格,那么这段代码就会重复出现多次。
Observer模式便是抽取了这种多个对象之间状态同步操作。

介绍

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

实现

Observer模式的静态图如下:

其中:
Subject维护一个Observer列表,Subject内部状态更新时通知列表中的Observer对象。
Observer声明Update接口,这个接口在Subject更新时被Subject调用,并保持Observer状态与Subject一致。

Observer模式的顺序图如下:

当Subject更新时它将通知各个Observer,Observer收到通知时可以查询Subject的状态,并同步自身状态。… Read the rest

设计模式:Memento

针对问题

有时程序需要记录对象的内部状态,在对象内部状态改变后可以利用记录恢复之前的状态。但是面向对象编程中通常封装了对象内部的状态信息,使得这些状态不能被其他对象访问,而暴露对象内部状态又破坏了封装原则。Memento模式利用独立的状态对象保存对象状态,解决了这两者间的冲突。

介绍

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

实现

Memento模式的静态图如下:

其中:
Originator提供两个接口:
1、创建Memento,并将自身状态保存在Memento中。
2、通过Memento对象恢复自身状态。
Memento对象可存入或取出Originator对象的状态。
Caretaker负责保存Memento对象。

Memento模式的活动图如下:

实现Memento模式时,需要注意以下两点:
1、Memento对象需要支持两类接口:为Originator提供的宽接口和为其他对象提供的窄接口,也就是说,应该对Originator以外的对象隐藏Originator相关的接口。C++中可以用友元函数实现。… Read the rest

设计模式:Mediator

针对问题

面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。在最坏的情况下,每一个对象都知道其它所有对象。
而系统设计中,这种相互连接会增加对象间的耦合度,系统将逐渐成为一个难以分割的整体,以至于对系统系统无法进行大的改动。
Mediator模式的作用便是分离“对象”与“对象之间的交互”逻辑。

介绍

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

实现

Mediator模式的静态图如下:

其中:
Mediator定义一个用于与各对象通信的接口(当仅有一个ConcreteMediator时可以不定义Mediator接口)。
ConcreteMediator实现具体通信逻辑并维护通信对象列表。
ConcreteColleague保存Mediator对象的引用,在需要与其他对象通信时,改为与Mediator通信。… Read the rest

设计模式:Iterator

针对问题

如果要遍历一个列表,可以为列表类型声明first/next/end等函数,并在其中封装具体的遍历逻辑。但是这么做有几个弊端:
1、如果需要以不同的实现方式遍历列表,那么可能需要声明多种遍历操作。
2、一个列表可能需要同时进行多个遍历。
解决的方法之一就是把遍历相关的操作提取到另一个类中,这就是Iterator模式。

介绍

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

实现

Iterator模式的静态图如下:

图中:
Aggregate为被访问对象的基类,它声明一个获取Iterator的函数。
ConcreteAggregate返回的ConcreteIterator实例,在ConcreteIterator中实现具体的迭代操作。

Iterator模式的实现要注意以下几点:
1、Iterator可分为内部和外部两种,外部Iterator由客户控制每一步遍历,内部Iterator只需要提交一个待执行的操作,Iterator负责对每一个元素执行该操作。… Read the rest

设计模式:Command

针对问题

假设要设计一个文本编辑器的“打开”按钮,点击之后显示“打开”对话框,之后在窗口中显示文档的内容。我们可以通过按钮类派生一个新类,重写Click处理
逻辑,在Click函数中执行以上的功能。
但这样设计的问题有两个:
1、如果需要多个按钮,那么每种按钮都需要派生一个新类。
2、如果要实现一个“打开”的菜单项,由于菜单不能继承自按钮,代码无法复用。
在这种情况下需要用某种设计模式将“调用者”与“算法逻辑”、“被操作者”解耦。

介绍

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

实现

Command模式的静态图如下:

其中:
Invoker为操作的调用者,例子中的“打开”按钮。
Receiver为被操作对象,例子中的文档窗口。… Read the rest

设计模式:Chain Of Responsibility

针对问题

在看电视新闻的时候经常会有这种情况:某一个记者去采访某部门,接待人员告诉他“这件事我处理不了,得找领导”
领导告诉他:“这件事不归我们管,得找xx部”,然后把电话转到xx部。
xx部的接待告诉他:“这件事我们也没辙,得找yy部”,然后把电话转到yy部。
在这种情况下,每一个部门都有可能处理这件事,但是记者也并不知道最终谁会出面处理,也不知道能不能处理。
把记着比作调用者,把接电话的每个人比作处理类,就形成了责任链模式。

介绍

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

实现

责任链模式的静态图如下:

每一个潜在的调用处理者都需要继承Handler类。Handler类需要做两件事情:
1、声明HandleRequest方法。… Read the rest

分类目录