V
VRGL
Unregistered / Unconfirmed
GUEST, unregistred user!
之一
设计模式自GOF的书出版后,已成为面向对象技术的主流分支之一.但GOF的书有些晦涩,特
别对缺乏面向对象基础的同志来说,亦是一个挑战.其实,GOF的书名是一个很好的暗示设
计模式:可重用面向对象的软件的基础Design Patterns: Elements of Reusable Objec
t-Oriented Software),即:第一,她是建立在面向对象的概念和设计原则基础上;第二,她
的目的是获取重用的可能.
对于设计模式的理解,第一点是非常重要的,我们可以用面向对象的基本概念去理解设计
模式,面向对象的基本概念是什么呢?最基本的是封装(encapsulation),抽象(abstracti
on),多态(polymorphism),继承(inheritance).
封装通俗的含义就是,什么都是对象(everything is an object).为什么要封装呢?类(c
lass)的责任(responsibility)被分离出去,变化被局部化了,增加了可重用的可能.一个
类的责任越独立,单一,它的可重用的可能性也就越大,实际上我们在面向对象的分析和设
计过程里,就是不断里求精(refine)分解(decompose).在设计模式里,命令模式(command
)无非是一个操作被封装成了一个对象,策略模式(strategy)无非是一个算法封装成了一
个对象.类工厂模式(factory method)是将创建对象的职责委托给了另外一个类,其实它
是使用对象和生产对象两个职责的分离,为什么要分离?重用的可能性增加了.其实,这里
给了大家一个思路,究竟什么是对象?THREE AMIGOS给出了三类对象:实体对象(entity),
控制对象(control),边界对象(boudary),这是一个非常好的类发现的指引.三类对象的参
考一般在分析阶段实现用例(use case)时应用.增加对象其实就是我们的设计(design)活
动,增加了一个间接的层次,而不是直接去实现功能,那是under-engineering.
抽象的含义是什么呢?什么时候有抽象活动发生呢?一般现实的途径是,有共同特征时
就可以抽象,共同特征意味着在不同的个体间存在稳定性,在时间的演化过程里也存在
稳定性。稳定性正是我们可重用的基础,我们可以假设未来的个体对象具有现在抽象出
来的特征。因此,每一个对象都有一个接口(every object has an interface), 其实
我们在GOF的书里的每一个类图(class diagram)里可以发现,每一个类都有一个接口
。抽象具体表现形式是抽象类(abstract class),接口(interface)和模板类(tem
plate class)。抽象类是要去实现继承的关系,单论关系而言,基类(base class)与
子类(sub class)是一个严格的紧耦合(tightly coupling)关系,它影响了类的重用
可能,所有就有了装饰模式(decorator)和组合模式(composition)代替继承来扩展
类的功能。接口分离了实现,它是面向客户的,即它更多地面向功能实现。而类的设计
在系统内部,因此类的设计与类接口的设计的目标是不一样
的,前者追求重用性,越来越精细(fine),后者要为客户解决问题(实现功能需求)
提供一个简单一致的接口,因此它是稳定的,粗粒度的,这是矛盾,协调矛盾的模式是
facade模式。其实根据面向对象可跟踪性(tracability),facade可以理解为一个控制
对象(control object)。跟接口相关的模式还有adapter,bridge。至于模板类,在模
式里就有template这个模式。
多态是什么呢?动态绑定,也是在运行期(runtime)来决定由哪个对象来执行某个操作。
运行期与编译期相比较,当然是运行期变化好,至少我们可以省略一次编译的过程。vi
sitor模式是一个典型应用多态的例子,是我们常说的回调的方法(call back)。
设计模式的目标是重用,我们应用设计模式可以从重用着手。重用首先要清楚的问题是
:什么在变化或将要;第二,怎么适应变化。具体的技术是将变化局部化,即封装,第
二条是接口与实现分离,接口保持稳定,实现可以变化。
总之,设计模式的意义在于它是重用结果的一个非常形式化的表达,也为我们创建重用
结果提供了一个规范。重用是经济性的体现,这正是软件工程作为一项工程(project)
经济活动非研究(study)的假设前提,即:工程是在现有的技术条件下必然能实现的,因
此,软件工程活动的最终依据是经济性,这正是我们强调重用的原因。
之二
Bruce Eckel在think in patterns(www.mindview.net)写道:GOF的模式分类有些严格
,其实很多模式结构(uml类图)类似,只是语义有别(semantics).可以做论据的是pro
xy模式和decorator模式,还可以算上composite模式.结构类似意味实现大同小异。依赖
模糊的语义来区别和应用各个模式,当然只是雾里看花了。设计模式的理解和应用搞清
楚五个问题:第一,静态结构是什么(UML类图);第二,运行期(runtime)的实例的
调用关系是什么(UML顺序图);第三,模式能适应哪些将来的变化,变化是由什么技术
来适应的,这个技术的解释由面向对象的基本概念和设计原则来说明;第四,在top-do
wn和bottom-up的设计方法时怎么应用模式;第五,设计模式是一个设计渐进演化的过程
的结果,在我们初始直接实现功能的设计方案里有哪些变化不能适应,如果要适应变化
,我们应该如何改进这个设计,其实大家应该知道了,这就是refactoring。Bruce Eck
el在他的书的第12章 pattern refactoring 有一个设计演化的例子,大家可以去好好研
究,得出自己的体会。至于pattern带来的over-engineering自是后话,跟极限编程(e
xtreme programming)倡导的简单设计原则千丝万缕。
以factory method模式开始我们的设计模式(design pattern)的理解。
factory method模式的结构之简单自不用多说,其含义是将创建对象的职责从使用此对
象的类委托(delegate)给一个新类——工厂类。应用的原则亦可简单地归纳为:如果
创建一个对象的代码超过两行,就可以封装此功能为一个类,隐藏生产对象的细节,因
为使用对象的类没有必要去了解生产的过程、配料。(这些关系完全可以类比到我们的
现实生活的关系,这个理论的依据来源于面向对象分析和设计的跟踪性(traceability
).)factory method模式适应什么变化呢?哪个角色(role)在变化?哪个角色没有变
化呢?客户端的程序(功能实现的程序)可以不变,生产对象的细节可以变化,但是对
客户端的程序没有什么影响,因为客户端的程序应用的是生产对象的接口(interface)
。factory method模式的应用形式可以多种多样,不要拘泥于一定要创建一个新类出来
,要记住的是,生产对象的职责在复杂的情况下要封装起来,成为系统设计的一部分,
而不要在系统外部去实现。factory method模式的一个典型的应用是数据库连接缓冲池
(connection pool)的数据源(DataSource)。
abstract factory与factory method有什么区别呢?从应用的观点来看,其实是一样的
。abstract factory模式的理解可以是:由工厂找到产品,大家注意,不是直接去找产
品,增加了一个间接(indirect)的层次,起什么作用呢?解耦(decoupling)。是谁
跟谁的关系解耦呢?uml类图清楚地说明了一切:产品类与使用产品类的客户端程序。工
厂类如果在外部通过配置文件来提供,就有了运行期(runtime)的灵活性--产品不是在
编译期(compile time)来确定的。实例为证:在javax.naming的包里javax.naming.Con
text.INITIAL_CONTEXT_FACTORY就是这个东东
,在JMS里常要配置JMS的connection factory,也是这个东东。怎么应用abstract fact
ory模式呢?如果你的代码里用到了一个系列的产品,而且创建对象的代码超过两行,你
就用它。
builder模式是一个将创建对象分解成创建各个部分,然后组合成一个对象,也就是对象
可以求精分解成部分对象,以重用它的创建部分的过程和结果。
至于singleton模式,就不想多说了。如果不明白,闭关再说。
简言之,大家不要拘泥于GOF的书,尽量有自己的理解,然后去应用它,慢慢体会和掌握
,就象模式的演化一样,这样思维不至于有太大的跳跃。不理解就是原因与结果之间的
逻辑没有找到。