,记录下来则需要经过沉淀、积累、思考,最后厚积薄发,方可小成。
设计模式之于面向对象系统的设计和开发的作用就有如数据结构之于面向过程开发的作用一般,其重要性和必要性自然不需要我赘述。
然而学习设计模式的过程却是痛苦的,从阅读设计模式的圣经——GoF 的《设计模式:可复用面向对象软件的基础》时的枯燥、苦闷、茫无头绪,到有一天突然有一种顿悟;自己去实现 GoF 的 23 中模式时候的知其然不知其所以然,并且有一天在自己设计的系统种由于设计的原因让自己苦不堪言,突然悟到了设计模 第 2 页 共 105 页 k_eckel设计模式精解-GoF 23 种设计模式解析附 C实现源码 http://www.mscenter.edu.cn/blog/k_eckel式种的某一个正好可以很好的解决问题,到自己设计的 elegant 的系统时候的喜悦与思考;一直到最后向别人去讲解设计模式,别人向你咨询设计模式,和别人讨论设计模式。
就如GoF 在其前言中说到:一旦你理解了设计并且有了一种“Aha!”(而不是“Huh?”)的应用经验和体验后,你将用一种非同寻常的方式思考面向对象设计。
这个过程我认为是漫长的,painful,但是是非常必要的。
经过了的才是自己的,Scott Mayer 在其巨著《Effective C》就曾经说过:C老手和 C新手的区别就是前者手背上有很多伤疤。
是的在软件开发和设计的过程中,失败、错误是最好的老师,当然在系统开发中,失败和错误则是噩梦的开端和结束,因为你很难有改正错误的机会。
因此,尽量让自己多几道疤痕是对的。
面向对象系统的分析和设计实际上追求的就是两点,一是高内聚(Cohesion),而是低耦合(Coupling)。
这也是我们软件设计所准求的,因此无论是 OO 中的封装、继承、多态,还是我们的设计模式的原则和实例都是在为了这两个目标努力着、贡献着。
道不远人,设计模式也是这般,正如我在《设计模式探索(总序)》中提到的。
设计模式并不是空的理论,并不是脱离实际的教条。
就如我们在进行软件开发的过程会很自然用到很多的算法和结构来解决实际的问题,那些其实也就是数据结构中的重要概念和内容。
在面向对象系统的设计和开发中,我们已经积累了很多的原则,比如面向对象中的封装、继承和多态、面向接口编程、优先使用组合而不是继承、将抽象和实现分离的思想等等,在设计模式中你总是能看到他们的影子,特别是组合(委托)和继承的差异带来系统在耦合性上的差别,更是在设计模式多次涉及到。
而一些设计模式的思想在我们做系统的设计和开发中则是经常要用到的,比如说Template、Strategy模式的思想,Singleton模式的思想,Factory模式的思想等等,还有很多的模式已经在我们的开发平台中扎根了,比如说Observer(其实例为Model-Control-View模式)是MFC和Struts中的基本框架,Iterator模式则在C的STL中有实现等。
或许有的人会说,我们不需要设计模式,我们的系统很小,设计模式会束缚我们的实现。
我想说的是,设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了 23 种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想融入到了你的思想中后,你就会不自觉地使用这种思想去进行你的设计和开发,这一切才是最重要的。
之于学习设计模式的过程我想应该是一个迭代的过程,我向来学东西的时候不追求一遍就掌握、理解透彻(很多情况也是不可能的),我喜欢用一种迭代的思想来指导我的学习过程。
看书看不懂、思想没有理解,可以反复去读、去思考,我认为这样一个过程是适合向我们不是有一个很统一的时间去学习一种技术和知识(可能那样有时候反而有些枯燥和郁闷)。
第 3 页 共 105 页 k_eckel设计模式精解-GoF 23 种设计模式解析附 C实现源码 http://www.mscenter.edu.cn/blog/k_eckelGoF 在《设计模式》一书中也提到,如果不是一个有经验的面向对象设计人员,建议从最简单最常用的设计模式入门,比如 AbstractFactory 模式、Adapater 模式、Composite 模式、Decorator 模式、Factory 模式、Observer 模式、Strategy 模式、Template 模式等。
我的感触是确实是这样,至少 GoF 列出的模式我都在开发和设计有用到,如果需要我这里再加上几个我觉得在开发中会很有用的模式:Singleton 模式、Faade 模式和 Bridge 模式。
写设计模式解析的目的其实是想把 GoF 的《设计模式》进行简化,变得容易理解和接受。
GoF 的《设计模式》是圣经,但是同时因为《设计模式》一书是 4 位博士的作品,并且主要是基于 Erich 的博士
论文,博士的特色我觉得最大的就是抽象,将一个具体的问题抽象到一般,形成理论。
因此 GoF 的这本圣经在很多地方用语都比较精简和抽象,读过的可能都有一种确实是博士写出来的东西的感觉。
抽象的好处是能够提供指导性的意见和建议,其瑕疵就是不容易为新手所理解和掌握。
我的本意是想为抽象描述和具体的实现提供一个桥接(尽管GoF 在书中给出了很多的
代码和实例,但是我觉得有两个不足:一是不完整,结果是不好直接看到演示,因此我给出的
代码都是完整的、可编译运行的;二是给出的都是一些比较大的系统中一部分简单实现,我想 GoF 的原意可能是想说明这些模式确实很管用,但是却同时带来一个更大的不好的地方就是不容易为新手理解和掌握),然而这个过程是痛苦的,也可能是不成功的(可能会是这样)。
这里面就有一个取舍的问题,一方面我想尽量去简化 GoF的描述,然而思考后的东西却在很多的时候和 GoF 的描述很相似,并且觉得将这些内容再抽象一下,书中的很多表达则是最为经典的。
当然这里面也有些许的例外,Bruce Eckel 在其大作《Thinking in Patterns》一书中提到:Bridge 模式是 GoF 在描述其 23 中设计模式中描述得最为糟糕得模式,于我心有戚戚焉!具体的内容请参看我写的《设计模式解析——Bridge 模式》一文。
另外一方面,我又要尽量去避免走到了 GoF 一起,因为那样就失去了我写这个解析的本意了。
这两个方面的权衡是很痛苦,并且结果可能也还是没有达到我的本意要求。
4 月份是我最不忙的时候,也是我非常忙的时候。
论文的查阅、思考、撰写,几个项目的前期准备(文档、Demo等),俱乐部的诸多事宜,挑战杯的准备,学习(课业、专业等各个方面)等等,更加重要的是Visual CMCS(Visual C_minus Compiler System)的设计和开发(Visual CMCS是笔者设计和开发的C_minus语言(C的子集)的编译系统,系统操作界面类似
VC,并且准备
代码分发和共享,详细信息请参考Visual CMCS的网站和Blog中的相关信息的发布), Visual CMCS1.0Beta终于在 4 月底发布了,也在别人的帮助下构建了Visual CMCS的网站 。
(http://cs.whu.edu.cn/cmcs ) 之所以提及这个,一方面是在Visual CMCS 第 4 页 共 105 页 k_eckel设计模式精解-GoF 23 种设计模式解析附 C实现源码 http://www.mscenter.edu.cn/blog/k_eckel的设计和开发体验了很多的设计模式,比如Factoty模式、Singleton模式、Strategy模式、State模式等等(我有一篇Blog中有关于这个的不完全的描述);另外一方面是这个设计模式解析实际上在这些工作的间隙中完成的,我一般会要求自己每天写一个模式,但是特殊的时候可能没有写或者一天写了不止一个。
写这些文章,本身没有任何功利的杂念,只是一个原生态的冲动,反而很轻松的完成了。
有心栽花未必发,无心之事可成功,世间的事情可能在很多的时候恰恰就是那样了。
最后想用自己在阅读、学习、理解、实现、应用、思考设计模式后的一个感悟结束这个后记:只有真正理解了设计模式,才知道什么叫面向对象分析和设计。
k_eckel 写毕于 2005-05-04(五四青年节) 1:010.3 与作者联系 Author K_Eckel State Candidate for Master’s Degree School of Computer Wuhan University E_mail frweiwhu.edu.cn1 创建型模式1.1 Factory 模式 问题 在面向对象系统设计中经常可以遇到以下的两类问题: 1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。
这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。
这里很容易出现的一个问题 n 多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就编写诸如 new ×××的
代码。
这里带来两个问题 1)客户程序员必须知道实际子类的名称(当系统复杂后,命名将是一个很不好处理的问题,为了处理可能的名字冲突,有的命名可能并不是具有很好的可读性和可记忆性,就姑且不论不同 )程序员千奇百怪的个人偏好了。
,2)程序的扩展性和维护变得越来越困难。
第 5 页 共 105 页 k_eckel设计模式精解-GoF 23 种设计模式解析附 C实现源码 http://www.mscenter.edu.cn/blog/k_eckel 2)还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。
这里的意思为:假设我们在类 A 中要使用到类 B,B 是一个抽象父类,在 A 中并不知道具体要实例化那一个 B 的子类,但是在类 A 的子类 D 中是可以知道的。
在 A 中我们没有办法直接使用类似于 new ×××的语句,因为根本就不知道×××是什么。
以上两个问题也就引出了 Factory 模式的两个最重要的功能: 1)定义创建对象的接口,封装了对象的创建; 2)使得具体化类的工作延迟到了子类中。
模式选择 我们通常使用 Factory 模式来解决上面给出的两个问题。
在第一个问题中,我们经常就是声明一个创建对象的接口,并封装了对象的创建过程。
Factory 这里类似于一个真正意义上的工厂(生产对象)。
在第二个问题中,我们需要提供一个对象创建对象的接口,并在子类中提供其具体实现(因为只有在子类中可以决定到底实例化哪一个类)。
第一中情况的 Factory 的结构示意图为: 图 1:Factory 模式结构示意图 1 图 1 所以的 Factory 模式经常在系统开发中用到,但是这并不是 Factory 模式的最大威力所在(因为这可以通过其他方式解决这个问题)。
Factory 模式不单是提供了创建对象的接口,其最重要的是延迟了子类的实例化(第二个问题),以下是这种情况的一个 Factory 的结构示意图: 第 6 页 共 105 页 k_eckel设计模式精解-GoF 23 种设计模式解析附 C实现源码 http://www.mscenter.edu.cn/blog/k_eckel 图 2:Factory 模式结构示意图 1 图 2 中关键中 Factory 模式的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现:Factory 中只是提供了对象创建的接口,其实现将放在 Factory 的子类ConcreteFactory 中进行。
这是图 2 和图 1 的区别所在。
实现 完整
代码示例(code) Factory 模式的实现比较简单,这里为了方便初学者的学习和参考,将给出完整的实现
代码(所有
代码采用 C实现,并在
VC 6.0 下测试运行)。
第 7 页 共 105 页 k_eckel设计模式精解-GoF 23 种设计模式解析附 C实现源码 http://www.mscenter.edu.cn/blog/k_eckel
代码片断 1:Product.h
代码片断 2:Product.cpp //Product.h //Product.cpp ifndef _PRODUCT_H_ include quotProduct.hquot define _PRODUCT_H_ include ltiostreamgt class Product using namespace std public: Product::Product virtual Product 0 protected: Product Product::Product private: class ConcreteProduct:public Product ConcreteProduct::ConcreteProduct public: coutltltquotConcreteProduct....quotltltendl ConcreteProduct .
上一篇:
基于SSH整合架构的应用研究
下一篇:
爱情只不过就是,爱与不爱