码迷,mamicode.com
首页 > 其他好文 > 详细

软件设计模式

时间:2015-08-31 13:23:48      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:

活用设计模式

一、设计模式的隐喻

武功套路是习武的门径。新手要一招一式地练习套路,烂熟于心之后,熟能生巧,在实战之中即可见招拆招、运用自如——此时习武之人已从“新手”成长为“好手”。“高手”则没有套路,实战之中只有自然反应,然而一招一式浑然天成、恰到好处,似有似无、无中生有。“高手”之上还有“高高手”,他们达到的境界非我等凭借金氏武侠小说可以揣测。

设计模式之于设计,好比套路之于武术。“新手”要一个接一个地学习模式,“好手”能够活用模式,“高手”则没有模式。

设计模式的“内功”是面向对象的基本原则。这些原则是“”,模式是“”。高手拼的是“内功”,对面向对象基本原则有了深刻的领悟,才能用好设计模式,避免“走火入魔”。

一般在设计模式著作的前几章都会介绍面向对象的基本原则,这几章非常重要。学通了这几章,后面的模式就不过如此了。学完了设计模式,也最好翻过头来重新看看这几章,保证会有新的领悟。

二、为什么使用设计模式

对任何设计都可以凭主观(对设计很难做出客观评价)判断得出它是一个好的设计,还是一个坏的设计。使用设计模式是为了避免坏的设计。Martin叔叔在他的著作《敏捷软件开发原则、模式与实践》中描述了拙劣设计的症状:

l  僵化性(Rigidity):设计难以改变。

l  脆弱性(Fragility):设计易于遭到破坏。

l  牢固性(Immobility):设计难以重用。

l  粘滞性(Viscosity):难以做正确的事情。

l  不必要的复杂性(Needless Complexity):过分设计。

l  不必要的重复(Needless Repetition):过多的重复。

l  晦涩性(Opacity):混乱的表达。

三、什么时候使用设计模式

Martin叔叔的书中有段话:

在学习它们(设计原则和模式)的时候,请记住,敏捷开发人员不会对一个庞大的预先设计应用那些原则和模式。相反,这些原则和模式被应用在一次次的迭代中,力图使代码以及代码所表达的设计保持干净。

在这段容易被读者忽略的文字中,我体会到这样几层含义:

l  代码是设计(这是Martin叔叔强调的一个观点,这个观点可以参考《敏捷软件开发原则、模式与实践》一书的附录D);

l  设计模式是为了使设计适应变化;

l  设计模式是重构的工具;

l  设计一开始就要保持干净、简单,以后仍然要保持干净、简单;

l  不能过度使用设计模式。

使用设计模式的目的是为了适应未来的变化,变化之所以存在是因为它的不可预知性——如果可以预知,则不能称其为变化。如何判断哪些需求可能变化,哪些需求可能不变,并且在最大程度上保持设计的干净、简单,这是些工艺问题,而不是工程问题。既然是工艺问题,那么就只能给出原则,不能给出标准。使用设计模式的大体原则可能是:对未来极有可能发生变化的问题给出最简单、修改成本最低的解。

四、避免过度使用设计模式

易维护的程序首先要易理解,这一点远甚于其他。在易理解的代码上才好维护。过分地使用设计模式会增加程序的复杂性和晦涩性,让程序不易理解,从而降低了程序的易维护性。

Switch语句曾经遭致诟病,许多重构的例子就是拿Switch开刀。我认为Switch语句是高效的语句,可以写出极优雅、简单的代码。在很多情况下,直接使用Switch语句比把它拆成若干个Class更“干净”。

再比如,有一段四百多行的代码负责整个系统的调度,如果未来的变化仅仅是修改这四百行代码而不会大量添加代码,那么把这四百多行代码集中在一个函数里面,比将它拆分成十来个Class更加容易维护。

五、讨论几个具体的模式

1、创建模式(Creational Pattern)

工厂模式(Factory Method)是常用的模式。工厂模式的应用情景明确,设计思想简单。从使用多态到只用一个静态方法,工厂模式的变化形式有很多。我习惯简单地使用工厂模式,也就是使用只有静态方法的工厂模式。下面的工厂模式代码简单、干净:

MyFactory.GetClassInstance().DoFunction();

类厂并不承载业务逻辑,需求变化对类厂的影响通常很小。因此使用重量级的工厂模式往往并不划算。一组包含层次关系的重量级的工厂类,可能意味着过度设计。

单例模式(Singleton Method)和工厂模式关系密切。从实现的角度讲,单例模式是工厂模式的一个特例,但是两个模式的应用情景不同,因此它们属于不同的模式。

抽象工厂模式(Abstract FactoryMethod)是工厂模式的推广。抽象工厂模式的应用情景更加特殊和严格。在一个使用抽象工厂的设计中,如果未来发生不同产品族各自演化的情形,那么抽象工厂模式就可能崩溃了。在实际应用中,不同产品族各自演化,最终分道扬镳的情形是有的,用户提出这样的需求的确让人“触目惊心”。在使用抽象工厂模式之前,一定要保证从现在到未来都能够用一致的方式使用这些产品族。

将工厂模式稍加变化可以得到建造模式(Builder Method)。工厂模式的“加工工艺”是隐藏的,而建造模式的“加工工艺”是暴露的。这点不同,使建造模式在更加灵活的同时也有失优雅。

2、模板模式(Template Method)和策略模式(Strategy Method)

模板模式和策略模式的应用情景类似,但实现方式不同,前者使用继承,后者使用委托

模板模式有可能是最“古老”的模式之一,在使用面向对象技术的早期,“继承”大行其道,很多设计人员可能不自觉地使用过模板模式。模板模式的缺点是把具体实现和通用算法紧密地耦合起来,使得具体实现只能被一个通用算法操纵。然而在继承关系中,父类的信息可以更多地暴露给子类,这种(违背面向对象设计原则的)微妙的沟通在一些特定应用中显得更加灵活和方便。

策略模式委托的经典用法。策略模式消除了通用算法和具体实现的耦合,使得具体实现可以被多个通用算法操纵。策略模式也增加了类层次,比模板模式复杂。

模板模式和策略模式通常可以互相替换。它们都像试卷,模板模式是填空题,策略模式是选择题

3、简化问题的模式

门面模式(Façade Method)把一组复杂的接口隐藏在一个简单且特定的接口后面。

调停者模式(Mediator Method)把对象之间的引用关系包装在一个特定的容器里面。

组合模式(Composite Method)描述了整体与部分的结构关系,并且允许用一致的方式处理这个结构。

上面几个模式对使用者而言,都在一定程度上起到了简化问题的作用。

4、扩展功能的模式

访问者模式(Visitor Method)和装饰模式(Decorator Method)都可以在不改变现有类结构的基础上,动态地增加功能。

访问者模式把现有类结构上的对象“分配”到一个名为访问者的类中,在访问者的相应方法中配置对象、改变对象或扩展功能。

装饰模式把现有类结构上的对象“注入”一个装饰类中,在装饰类中扩展它的功能。

访问者模式和装饰模式在实际效果上是不同的。访问者模式可以把对象分配到相应的方法里,从而对每个对象分别进行加工或扩展。而装饰模式只能用一致的方式所有的被装饰对象进行加工或扩展,要想实现不同的加工或扩展,只能增加新的装饰类。

过多的“装饰类”有可能使业务逻辑分散,并且使程序结构复杂。针对每一个具体的派生类,“访问类”都要有一个对应的方法,增加派生类的时候也要增加访问类的方法。扩展功能的需求是经常发生的,是否有必要使用上述模式则值得再三考虑。

5、其他常用的模式

桥梁模式(Bridge Method)。Class是封装了行为和属性的容器,然而Class的一组行为可能独立演化,这时最直接的想法是使用继承,把各不相同的行为封装在不同的子类里。桥梁模式从另外的角度解决了这个问题。桥梁模式把独立演化的行为封装在另外一个类体系里,与原来的类体系分别独立演化,两个类体系在抽象层次是“使用”关系。在很多OO教材里面用Shape类封装属性和Draw方法,在桥梁模式里,“形状”和“画笔”是两组独立演化的类体系,在抽象层次,“形状”使用“画笔”绘制自己。

适配器模式(Adapter Method)是常用模式,它比较简单,有时和其他的模式配合使用。

命令模式(Command Method)被Martin称为“最简单、最优雅的模式之一”。命令模式的魅力在于它为每个类“培训”出了相同的技能,经过“培训”的类“柔性”更强,能够产生不可思议的能力。

6、不太需要的模式

观察者模式(Observer Method)。Java和C#都实现了观察者模式。

迭代子模式(Iterator Method)。在Java和C#语言里,可以用聚集类代替。

备忘录模式(Memento Method)。可以用Class的序列化能力代替。

责任链模式(Chain of ResponsibilityMethod)。可以用其他的方式替代,例如观察者模式、语言本身提供的消息机制等。

解释器模式(Interpreter Method)。个人认为,它是个算法,不是模式。

代理模式(Proxy Method)。如果在一开始就知道某些底层策略一定会被替换掉,那么使用代理来隔离这些策略还是有必要的。否则,几乎没有使用的必要。

参考文献:

1.Gamma etc., DesignPatterns: Elements of Reusable Object-Oriented Software. Addison-Wesley1995.(中译本:《设计模式:可复用面向对象软件的基础》,李英军等译,机械工业出版社,2000年)

2.Robert C. Martin,Agile SoftwareDevelopment Principles, Patterns, and Practices.(中译本:《敏捷软件开发原则、模式与实践》,邓辉译,清华大学出版社,2003年)

 

作者:

张昱 曾就职于浪潮集团、联想集团,现就职于中科院电子所。超过十年的软件工作经验。对分析设计、项目管理、编程实践有着浓厚的兴趣。

--------------------------------------------------------------

参考:

tLEE——设计模式

yyyuhan——C++设计模式

MaoBisheng——设计模式

 

Pluginsin C++

Buildinga Better Plugin Architecture(C++)

BuildingYour Own Plugin Framework

软件设计模式

标签:

原文地址:http://www.cnblogs.com/fgcs/p/4772651.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!