第二章 实例研究:设计一个文档编辑器--《设计模式-可复用面向对象软件的基础》Erich Gamma

作者小感:

设计模式这本书,对于我来说,初学者看起来比较懵懂,稍微有些枯燥。所以得耐着性子看。看完每一章节,就会有成就感,也确实能够打心眼赞成这种设计模式。

第二章,是从设计一个文档编辑器这个例子,告诉大家:设计模式在应用中的作用,以及如何根据需求来判断使用哪种模式。

这个例子好长哦,一定要耐心。看完这个例子,更是加强了我学习设计模式的决心。

大家一起努力哦。^o^


Lexi文档编辑器设计时面临的问题:

(1)文档结构 。即文档物理结构的表示问题。文档中包含各种类型的图元,如:文字,图形,行,列,还有组合的图元。如何组织这些图元。

(2)格式化。如何构造文档结构,如:将文本分行,分列,用户制定边界宽度等等。

(3)修饰用户界面。 在文档区域周围加边界,加滚动条等。

(4)支持多视感标准。支持多种不同风格的用户界面。比如:按钮可以是矩形,也可是圆形。

(5)支持多种窗口系统。移植性问题。例如:窗口环境不同的窗口系统,他的大小得根据实际硬件大小来限制。

(6)用户操作。 用户操作有很多种,并且同一种用户目的,可由多种命令操作实现。比如:既可以通过菜单项来实现撤销,也可以通过键盘快捷键来实现。

(7)拼写检查和连字符。如何遍历不同数据结构存储的元素。如何对不同类型的图元进行检查。

(在本章中,大多数是使用类和对象的组合关系来实现,并不提倡继承方式)

下面,具体介绍每个问题。


(1)文档结构

总体思想:每种图元都是一种对象,对图元对象进行递归组合(recursive composition)。用到的模式为:Composite模式

 Composite模式可以表示复杂的、层次式的结构,描述了面向对象的递归组合的本质。

递归组合,可以由简单的元素逐渐建立复杂的元素,是我们用简单图元构造复杂文档的方法之一。在文档结构中,应该一致对待文本和图形,因此我们将这些图元抽象出来抽象类Glyph,不同图元(字符、矩形、行、列)是Glyph的子类。

(2)格式化即:Composite,组合

总体思想:将格式化算法抽象出来,作为格式化类Compositor类。一个Compositor类的子类可以实现一个各自的不同格式化算法(如,不同的分行算法)。格式化类Compositor类和他的子类构成了一个格式化类层次,封装格式化算法。用到的模式为:Strategy模式。

Compositor格式化的元是Composition图元的各个子图元。Composition 类中包含(聚合一个Compositor类型的对象;Compositor类中包含(关联)一个Composition *类型的指针。一个Composition创建时候得到一个Compositor子类的对象,composition需要格式化的时候,它的Compositor对象调用Compositor::compose()操作该操作遍历composition的各个子图元,并进行格式化

这里用到的Strategy模式,该模式封装了策略和操作环境。compositor是策略(格式化算法),composition(组合的图元策略的环境。Compositor和Composition的分离确保了文档物理结构和不同格式化算法之间的分离,同时这两个类又存在向的聚合和关联关系。

(3)修饰用户界面滚动条,文档边界等就是修饰

总体思想:为了便于增加和去除这些修饰所以不应该过继承方式将他们添加到用户界面。所以在这里使用对象的组合,把修饰看做是对象,组合是一种潜在的灵活的扩展机制。

MonoGlyph是Glyph的子类,同时,MonoGlyph类中包含一个Glyph图元引用

我们将修饰类MonoGlyph(子类为Scroller,Border),作为Glyph的子类,也就是说,修饰类对象也就是一种图元,只是绘制方式不同而已。MonoGlyph::draw(//在此,调用组合图元的draw();  )负责绘制了边界外的图元,而他的子类Border的Border::draw()绘制修饰元边界。

这里用到的模式为Decorator模式,该模式描述了以透明围栏来支持修饰的类和对象的关系,修饰是指给一个对象增加职责的事物。透明围栏(Transparent Enclosure)使得客户分辨不出来实在处理组件还是组件的围栏。在这里,是指将修饰和图元组建都作为Glyph的子类,并不围栏作为特殊的另外一个类层次来对待。

(4)支持多种视感标准

可能大家对于视感标准不太理解。我觉得不同的视感标准,就是类似与MFC界面美化皮肤,使用不同的皮肤,界面上的控件具有不同的风格

总体思想:我们文档编辑器应该能支持已有的视感标准,也应在新标准出现时候能够支持。所以,应该避免显示调用一种具体的标准,而且能够很容易替换一种标准而使用新标准。因此,我们可以通过抽象对象的创建过程来实现上述目的。

GUIFactoty为抽象工厂类,他具有MoniFactory, PMFactory, MacFactory等子类,这些子类是不同的视感标准

在这里用到的是Abstract Factory模式。工厂和产品是该模式的主要参与者。描述了怎样在不直接实例化类的情况下创建一系列相关的产品对象。它最适用于产品对象的数目和种类不变,而具体的产品系列之间不同的情况,通过实例化具体的工厂对象来选择产品系列。
(5)支持多种窗口系统

总体思想:对不同的窗口系统做统一的抽象,再对各窗口系统(子类)实现做一些调整,使之符合公共的接口。

定义一个抽象窗口类Window类,他的子类有ApplicationWindow(应用窗口)DialogWindow类对话框窗口)等。对变化(窗口系统)进行封装。定义一个独立的WindowImp类层次来隐藏不同窗口系统的实现。WindowImp是封装了窗口系统相关代码的抽象类。

WindowImp类定义了一个公共窗口系统设施的接口.Window类接口针对于程序员,而WindowImp是针对窗口系统的。将窗口功能分离到这两个类中,我们就可一独立实现这些接口,使得无需修改就可运行在多窗口系统中。

这里用到的是Bridge模式。Bridge模式的目的是允许分离的类层次在一起工作,即使它们是独立演化的。

(6)用户操作

总体思想:用户请求多样,因此封装请求,抽象为Command类。

Command模式,描述了如何封装请求,也描述了一致的请求接口,允许配置客户端以处理不同的请求。一个命令可以将所有或者部分请求实现委托给其他对象,也可以不进行委托。适合于 为分散功能提供集中访问接口。

(7)拼写检查和断字处理

总体思想:这部分需要对不同的数据结构进行遍历和访问(相应处理)

可以使用Iterator抽象类为遍历和访问提供一个通用的接口。通过继承来统一访问不数据结构和支持新的遍历方式,同时不改变已有的图元的实现。

用到的Iterator模式,支持访问和遍历对象结构,抽象了遍历算法,对客户隐藏了遍历对象的内部数据结构。

拼写检查和分析可以抽象为一个visitor类,该类的子类可利用迭代(Iterator)访问图元并做相应的分析操作。

用到的Visitor模式,允许无限扩充分析能力而又不会使得文档结构的实现复杂化。




阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页