——之软件设计原则
作者:谈发中
Email:tanfazhong@gail.com
QQ:250175280
1
前言: 1.1
近日学习《JAVA与模式》,初看一两遍,简得其义,揣摩其意,深感不得其中精髓,更谈不是灵活应用于实践之中,欲求于网络同行之读书笔记,其意大都是书中摘录,亦无所获;故而私下记录心得体会,一来以拱众人证明并予指正,以便提高,二来以便其他初学者共同学习提高理解之用。
多年来,同行非常注重软件设计的:可维护性,可复用性,可扩展性和灵活性,并以此为设计目标;而书中记录下的几大设计原则,为这个宏伟的目标铺平了道路;这些设计原则对于设计而言,不同人有不同层次的理解,设计的作品的水平也参差不齐,这也说明也其学习是一个长期地过程;在这个过程里,我们要反复琢磨、讨论,然后实践,以此反复。
2 概义 2.1
2.2
一个糟糕的设计会出现许多令人头痛的问题,这些问题在《JAVA与模式》P.35.中摘录了下来:“过于僵硬,过于脆弱,复用率低,黏度过高”。这些问题在书中也摘录了其对立性的原因:“可维护性,可复用性,可扩展性与灵活性”;为此大家为实现这个目标提出了——“法”。 韩非子讲:“国无常强,无常弱。奉法强,则国强;奉法弱,则国弱”;可见对这原则——“法”是多么地重要;而且认识、理解、普及“法”,使之成为“法制社会”。
模式的核心——道 3.1 阐述我所谓的:“道”,先让我们来认识我说的:“问题领域”: 3.2 我把我所谓的的问题领域分成两部份,“静态问题领域”和“动态问题领域”;我
们从小到大学习了这么多知识,对一类的事实都有一些共同的看法,或都称它们为知识,我叫它静态问题领域;随着时间的推移,这些事物会发生变化,比如人会老去,但他还是那个人;这类变化的问题我称之动态问题领域;当然这两都间都有联系,也存在着转化,如我用太极图(图A)表示:
3
4
静态问题领域与动态问题领域的表示方法:
4.1 首先树型数据与继承等级结构在语义是是想等的;而合成模式与装饰模式也可以
生成的链式对象结构,这与线型数据结构也是雷同的。
4.2 A.静态问题领域:继承等级结构一但确定下来,改变起来就很困难,想重构代码
就要花很大的精力(图B),用它来描述静态问题领域再好不过了(因为运行继承的代码比运行动态联结的代码快,而且易于管理);
4.3 B.动态问题领域:a.图D中有线型数据结构(合成模式和装饰模式<图E>可以
将它们将对象生成线形结构),用它来描述动态问题领域。
1
打印时间:2013年4月4日星期四10:03:55 AM
诠释模式
——之软件设计原则
作者:谈发中
Email:tanfazhong@gail.com
QQ:250175280
4.4
4.5
b.图C是桥梁模式,这个模式之所以妙就是利用对象引(关联)把抽象化角色与实现化角色脱耦了;所以接口成了关联、脱耦的重要工具了。(注意:1:接口只是用来代表一个角色,多个角色是对接口的污染——接口隔离原则;2:理会这个模式对于理会策略、状态命令、观察者、建造模式很有意义)
接口的本质:它本身用来表示一个角色,而角色可以代表动态问题领域的一种可变性,它用来参与与静态问题领域的关联,从而形成动态引用。(使用接口与合成聚合模式的好久详情请见《java与模式》一书)
图CComponent+Operation()+componentConcreateComponentDecoratorConcreteDecorator图E
5
细化问题:
5.1 解决这个问题领域论的模型最终是要用代码来实现的,既然如此,我们将这些代
码分成许多小块,这些小块比函数小,又具有一定的语义,这些小块用集合中的元素表示,称它为元素代码。
5.1.1 作用与效果:如果用继承等级结构(树型数据结构)和合成模式与装饰模式
(线型数据结构)来组织元素代码,而且元素代码划分得非常合理,我们可以将代码复用的目的达到最大限度。
5.1.2 步骤:元素代码之间不组合形成不同行为,不同的行为又组合成不同的类;
而这些类之间又有相同的元素代码,从而组合成了继承等级结构与链式结构;这个过程要用分类思想来作指导,结果要使类从分类学上有意义。
5.2 用继承的工具来描述这些组合,共同的元素代码尽向上移,数据尽量向下移;这
样做的好外非常明显,一来这种组合已经定义好了,二来在新的需求下,找准自己想要的结点来复用已有的代码,使之成为该结点下的叶子结点;缺点就是这个组合早已经成为定局,想从新组合就非常困难。
5.2.1 B.a.用合成模式、装饰模式动态生成对象链,让它们动态联结代码,这样
的确非常灵活,但这样的小类太多了,实在难于管理。好处就在于解决了继承等级的缺点;这好比一个男人在外面有了太多的女人,把关系搞得过于复杂,此人虽然艳福不浅,但也有隐痛啊!比如金庸先生的《天龙八部》里的段正淳就是一例。
5.2.2 b.静态问题领域可以用一个接口的形式来管理动态生成的对象链,它可以用
来代表一个角色,从而封装一种可变性;是支持角色的一种机制;也可以这
2
打印时间:2013年4月4日星期四10:03:55 AM
诠释模式
——之软件设计原则
作者:谈发中
Email:tanfazhong@gail.com
QQ:250175280
6
7
8
9
样理解:静态问题领域是消费者,实体角色是产品,接口是说明书。
两种问题领域之间的关系:
6.1.1 静态问题领域与动态问题领域的转化:问题领域中不确定的变化的现像,在
经过长期实践是可以转化静态问题领域的知识,而静态的知识随着时间的变化也是会过时的。
6.1.2 例如:几亿年前,猴类随着时间、环境的变化,最终进化成为人类;那你有
可能会问,如果人不思劳动,像动物那样天天只知道吃喝睡玩乐,会退化为之前的猴吗?这个问题我想没有人知道,应该由时间来证明,呵呵!不过这就是归纳总结知识,然后再将这些知识运用与生活,然后再归纳与总结,如此反复,才得以发展;这就像钱一样,你存到银行对你来说并没有发挥它的作用,如果你把它用来投资,使它运作起来,才得以实现它的价值——属于你的摇钱树,你想要一棵吗?
6.1.3 这种关系的转化还有另一种表述——进化,演化,用这个词来形容,说明了
在软件系统生命周期里,它需要这种变化来适应现实情况;如果设计考虑到这种进化,那么代码的灵活性将非常高。(注意我说这种进化并不是指封装一种可变因素,那怕是继承等级结构)
6.1.4 以上我用两种工具:抽象类的继承等级结构与链式对象结构,和一个思维方
法:组合元素代码块,以及静态问题领域和动态问题领域之间的关系来阐述了图A。
6.1.5 在此声明我不是故作高深玄妙,我要把这些模式模式简单化,简单到不能再
简单的地步,直指问题的核心,这个核心问题我称它为:“道”。
对道的理解
7.1.1 不管是建立的模型是解决的那些问题,所对的对象都是现实世界的事物;而
这些事物都会随着时间的推移发生着变化,而这个物质世界所有的事物只有变化着、运动着,才得以有存在的意义,这种运动与变化我用老子的一个“道”字来形容;而我们又只有对我们所研究的对象有全局的认识并把握,之后才能得道,才能设计软件模型,才能理解模式,运用模式;道就在问题领域的运动之中,就在脑海与荧屏之间,代码与文档之间,文档中有模式,模式中存在道,道存在于我们吃饭的时候,在我们上班的路上,在你跟美女之间„„。
软件设计中的设计原则——“法制” 8.1 此“法制”是为了达到设计目标:“可维护性,可复用性,可扩展性和灵活性”
而制定的;理解这些设计原则需要与各种模式及多个项目的参考的基础之上,才能体会其中的意思。 这些原则之间的关系
9.1 开闭原则讲的是一个软件实体应当对扩展开放,对修改关闭。开闭是目标,依赖
倒转原则是步骤;依赖倒置原则是手段,机制
9.2 在继承等级结构中里,讲的是共用代码要向上移,数据向下移;目的并不只是为
3
打印时间:2013年4月4日星期四10:03:55 AM
诠释模式
——之软件设计原则
作者:谈发中
Email:tanfazhong@gail.com
QQ:250175280
9.3
9.4
了代码复用,它还可以引用父类的地方,子类也可以出现;因此我们用继承等级结构来组织代码,并遵循Coad条件(java与模式P.64.);在我们编码时讲究这些,也就达到了里氏代换原则的要求。这是不是实现开闭原则的步骤呢! 当我们还是初学者的时候,都喜欢用已有的类作为父类,从而来感受OO的好处;现在才明白这种复用的工具是在OOD的时候就已经决定了的,所以在一般情况下使用组合聚合关系来达到复用的目的是有一定道理的。这样做不但没有滥用继承(到底滥用了没有也许只有以后才能发现,当发现时来重构就要花时间了),还从一定层度上支持了里氏代换原则。
如果我在编码的时候尽量引用高层次的抽象类、接口,这样就做到了细节依赖于抽象,这就是针对接口、抽象,不针对实现编程,从而也就达到了依赖倒置原则,此过程就是做到了开闭原则的机制和手段。
9.5 9.6 9.7
如此我们的代码在可维护性,可复用性,可扩展性和灵活性方面是不是就大了呢! 首先我们得认识接口本身是用来作类型声明的,抽象是用来作继承用的;而接口是用来代码一个角色,类是用来代表一个分类、一个事物;接口隔离原则为什么不要接口原则就是这么一个道理,因为接口是用来表示一个角色而不是二个或者多个。
9.8 类可以继承一个接口,因此类就成了这个接口的实例、演员;类可以引用一个接
口,这个类就可以拥有很多角色的实例、演员,因此这个类从用户角度来讲同一意义的事情、职位可以由不同的事物、人来充当,从开发人员的角度来讲就是抽象化角色与实现化角色脱耦。
9.9 合成聚合原则是继承复用工具的一种替代方案,并充分运用了接口的好处;在模
式中的装饰模式就把这种意图体现得淋漓尽致。另外桥梁模式也正是引用了这一原则把实现化角色与抽象化角色分离,使得其它模式(如:状态模式、策略模式、观察者模式和命令模式)都利用了这一特长。{通过深刻理解了这些原则之后,也许我们自己也可以创造另外一个实用的模式出来} 9.10 最近听一朋友说:“处事的啊,把关系搞得越简单就越好”;圣人老子也这样讲,
使民无知,不相往来;初一看,跟大多数人的观点一致,认为在当时的时代,各国为了私欲年年混战,民不聊生,各国争用贤才;所以很多评论说在老子的那个时代,这种观念来治国很适合当时情况,现在看来,我不能赞成这样的观点了,因为这样理解只停留在字面意义上;假如我们把我们身边的朋友,邻居的关系处理成:交往没有利益共享,交往没有冲突原因,虽不是血亲那样亲密,但彼此相互尊重,如此人生也会少一些不必要的、无意义的矛盾。
9.11 我想迪为特法则的用意就在于此,我们现在来看看不遵守这个法则会怎么样,我
见过好多系统每一个类里有几十个函数,在这样一个关系复杂的系统里分的类也
打印时间:2013年4月4日星期四10:03:55 AM
4
诠释模式
——之软件设计原则
作者:谈发中
Email:tanfazhong@gail.com
QQ:250175280
不多,对象之间的关系相当复杂,如果想升级,我相信作者本人也要花费非常大的力气。
9.12 再回头看看图F和图G,图F是为了a.而作说明,图G是为了说明b.;观点a(F
图)说明了继承等级结构生成与作用及三原则的关系;观点b(G图)也说明了整体与部分的运用以及与开闭原则的关系;如果在遵守两图包含的5个原则再加上迪为特法则,那么这个系统的可维护性,可复用性,可扩展性和灵活性方面,将大有增加。
9.13 因此我们作为初学者,不但要养成好习的习惯,还要在开发的时候一定要对问题
要有一个全局的认识,把属于角色(动态问题领域)的部分提取出来,用接口这个工具把共同性抽象出来;对于属于静态问题域的方面,用继承等级结构来表达;这两方面都在语义上有一定的意义,而且尽量划分成小类;在代码实现的时候,尽量引用高层次的抽象类或者是接口。最后我们在随时总结知识,并把它们归纳成自己的语言,形成自己的知识,最终有一套属于自己的理论——真理,然后我们再推广现实生活并加以验证,如此反复。
打印时间:2013年4月4日星期四10:03:55 AM 5
因篇幅问题不能全部显示,请点此查看更多更全内容