连载:面向对象葵花宝典:思想、技巧与实践(38) - 设计模式之道

很多人能够熟练背诵出所有的设计模式,能够快速画出各种设计模式的UML类图,也能够熟练的写出《设计模式》一书中各个模式的样例代码。但一到实际的项目设计和开发的时候,往往都会陷入迷茫:要么无从下手,不知道哪个地方要用设计模式;要么生搬硬套,胡乱使用设计模式,将方案和代码搞得一团乱麻。

===========================================================================

【知易行难 —— 设计模式应用的问题】

形而下者谓之器,形而上者谓之道。

                                               ---《易经·系辞》

 

正如很多流行的技术(面向对象、UML等)一样,几乎大部分人都会宣称自己“掌握、熟练掌握”,甚至“精通”,然而,真正掌握的或者精通的,实在是少之又少。

 

一种典型的现象是:很多人能够熟练背诵出所有的设计模式,能够快速画出各种设计模式的UML类图,也能够熟练的写出《设计模式》一书中各个模式的样例代码。但一到实际的项目设计和开发的时候,往往都会陷入迷茫:要么无从下手,不知道哪个地方要用设计模式;要么生搬硬套,胡乱使用设计模式,将方案和代码搞得一团乱麻。

 

这是什么原因呢,难道是设计模式不好用,或者设计模式根本就是一个噱头?

答案不在于设计模式本身是否有用,而是在于我们没有掌握正确的学习和应用设计模式的方法。

 

学习《设计模式》一书中的23个设计模式,只是掌握了《设计模式》的“器”,但并没有掌握设计模式的“道”。就像一个工匠,锯、钻、锤、刨样样精通,但如果不知道什么地方该用锯,什么地方该用钻,肯定是一个不合格的工匠。为了能够更好的学习和应用设计模式,我们也需要掌握设计模式的“道”。

 

设计模式的“道”就是用来指导我们什么时候用设计模式,为什么要用设计模式,23个设计模式只是告诉了我们how,而设计模式之道却可以告诉我们why和where!

 

【拨云见日 —— 寻找设计模式之道】

熟悉《设计模式》一书内容的同学可能会想到:《设计模式》一书中,不是每个模式都有“适用性”的说明么?这个其实就是回答了where和why的问题啊!

 

例如:Facade模式的“适用性”说明如下(摘自《设计模式》中文版一书):

 

上面这一段文字,看起来回答了where和why的问题,但实际上我个人感觉作用并不大。

 

首先,这段描述太长了:以上这段文字是否花了你几分钟的时间去阅读和理解?

 

其次,这段描述比较抽象:什么事复杂,什么叫做简单,什么叫做很大依赖性。。。。。。可能每个人理解都不一样。

 

再者,23个模式,所有的“适应性”条款加起来估计有几十条条,你能够背住么?即使你能够全部背住,你能够全部理解么?即使你能够全部理解,当面对一个具体问题的时候,你知道几十条里面哪一条适应你的情况么?

 

所以,《设计模式》一书关于“适用性”的描述,实际上还是太复杂,太多了,不具备很强的实践知道意义和可操作性。

 

我们需要的是一个更简单的指导思想,大道至简,最好是一两句话就能够描述!

幸运的是,答案竟然就在《设计模式》一书中,但这个答案并不是那么明显!

 

《设计模式》一书的内容侧重点是23个模式的详细阐述,大部分人可能都是直奔主题,逐一去研究每个模式,而对于开头部分第1章和第2章的内容并没有详细研读和思考,或者对于这两章只是简单的浏览,并未认真领会和思考,由此错过了最重要的内容。再加上GoF在这2章的内容中,既要引入一个全新的概念,又要提纲挈领的介绍各个模式,还要引入实例进行分析,以至于大量的内容将真正核心的内容反而给淹没或者冲淡了。

 

设计模式之道就隐藏在“2.6.2 封装实现依赖关系”的最后一段,很简单的一句话:

对变化的概念进行封装(encapsulate the concept that varies)

 

你看到这句话可能有点失望,前面分析了那么久,卖了那么多的关子,结果就这么简简单单一句话,这不是在忽悠么?

你可千万别小看了这句话,“大道至简”,设计模式之道也不例外,但“简”并不意味着没用,相反,正因为其“简”,每个人的理解才一致,也更好掌握,实践中才更好应用。正所谓:“真传一句话,假传万卷书”。

 

GoF在《设计模式》一书中最早提出这个原则,后来不断的有其他专家进行阐述,其中《设计模式精解》(《Design pattern explained》)一书的阐述我认为是最精辟的:Find what varies and encapsulate it,翻译一下即“找到变化,封装变化”。虽然含义和GoF描述的基本一致,但其更加容易理解。

 

正所谓:踏破铁鞋无觅处,得来全不费工夫!

【庖丁解牛 —— 解析设计模式之道】

现在,让我们来深入理解“找到变化,然后封装变化”的设计模式之道。

首先,“找到变化”解决了“在哪里”使用设计模式的问题,即回答了“where”的问题。

 

“找到变化”看起来是比较抽象的一句话,但在实践中非常好应用和操作,而且不同领域、不同行业的系统都可以完美的应用这句话。虽然不同领域、不同行业变化的因素、方式、时机等都不一样,但每个领域或者行业的需求分析人员、设计人员,对自己所处行业和领域的可能变化肯定是有比较深刻的理解的,什么会变化、会如何变化、什么时候会变化。。。。。。等等,肯定都能够自己判断,这种判断并不需要什么高深的技巧和知识水平,只需要一定的经验积累。

 

如果我们刚接触一个行业或者领域,经验积累并不够,那怎么办呢?是否就无法“找到变化”了?

其实也不然,有一个万能的办法,只是要花费更多的精力了。

 

我的这个万能办法就是“唯一不变的是变化本身”,也就是说,如果你不知道什么会变化,那么就抱着怀疑一切的想法,一切都可能是变化的。

 

但光有这条指导原则还不行,如果我们真的抱着“一切都是可能变化的”想法,然后封装一切变化,那么就会陷入变化的漩涡无法自拔,因为变化是会递归的,A可能变成B,B也可能继续变化,于是这样无穷无尽,系统是不可能做出来的。

 

所以我们需要一个终止条件,避免陷入无穷无尽的变化递归漩涡。这个终止条件就是“有限时间内可能发生的变化”。这里的“有限时间”随行业和领域的不同而变化。例如(以下时间仅供参考):

互联网行业可以说:半年内可能发生的变化。。。。。。

电信行业可以说:1年内可能发生的变化。。。。。。

金融行业可以说:2年内可能发生的变化。。。。。。

政府行业可以说:3年内可能发生的变化。。。。。。

 

有了这个指导原则后,你可以这样去问有经验的前辈、大虾、大牛等: XXX在1年内会发生变化么?会怎样变化?

 

就这样,即使你是菜鸟,通过这么一招“借花献佛”,也能够轻松发现“变化”的地方。

 

其次,“封装变化”解决了“为什么”使用设计模式的问题,即回答了“why”的问题。

为什么我们要用设计模式,是因为我们要封装变化!但我们为什么要封装变化呢?

答案很明显:变化不好!

 

当然这个“不好”不是从业务的角度来说的,而是从系统的角度来说的。从业务的角度来说,“变化”是好的,变化意味着新的机会;但从系统的角度来说,变化并不好,因为变化必然要求系统改动,改动就意味着风险!

 

虽然变化给系统带来风险,但我们不能因此而“拒绝变化”,因为拒绝变化就意味着失去了机会,简单来说,赚不到钱的系统,设计再优美,功能再强大,系统再稳定,也不过是一堆无用的摆设:

客户给你提了新需求,你不做,能拿到合同么。。。。。。

行业正在兴起新的流行功能,你不做,你的系统有人用么。。。。。。

一项创新带来了新的机遇,你不做,能抢占市场么。。。。。。

 

所以我们要“拥抱变化”,但我们又不能让变化带来太大的风险,所以就提出了“封装变化”。“封装变化”意味着将变化的影响范围控制最小,将风险降到最低。

 

我们来看看,变化会带来哪些问题和风险:

1)开发人员需要编码以适应变化,设计不好的方案将导致大量的编码工作量、自测工作量;

2)测试人员不单要测试因变化而新增的那部分,还要测试受影响的部分,设计不好的方案,牵一发而动全身,导致测试工作量大大增加;

3)如果为了适应某个变化而对系统做了比较大的改动,则系统的质量风险将上升,很可能导致上线失败,或者上线后出现各种问题;

 

因此,我们要尽量减少变化带来的工作量和风险,而减少的最有效方法就是将变化的影响范围缩小,即:将变化封装起来,使其只在有限的范围内有影响。

 

【举一反三 —— 活学活用设计模式之道】

就像一个武林高手有了深厚的内功,天下万物皆可成为手中的利器,而不必拘泥于具体的武器和招数一样,掌握了设计模式之道后,我们其实也完全可以不拘泥于只是用《设计模式》一书中的23个设计模式,可以根据需要选择最合适的方案。

 

例如:

不同的业务有不同的规则排列组合,规则引擎可以封装各种变化的规则。。。。。。

类之间的依赖是变化的,Spring使用XML配置文件来封装这种变化。。。。。。

每个银行的卡都不一样,银联封装了这种变化,使得不同银行可以互通。。。。。。

 

总之,你可以使用类和设计模式来封装变化,你也可以使用配置文件和模块来封装变化,你也可以使用一个系统来封装变化。。。。。。

================================================ 
转载请注明出处:http://blog.csdn.net/yunhua_lee/article/details/38315995
================================================ 

时间: 2024-10-31 02:10:51

连载:面向对象葵花宝典:思想、技巧与实践(38) - 设计模式之道的相关文章

连载:面向对象葵花宝典:思想、技巧与实践(26) - 类模型三板斧

类模型设计其实就是程咬金打天下 -- 三板斧 而已 :) 第一斧(照猫画虎):领域类映射 面向对象类设计首先要解决的一个问题是:类从哪里来 ? 有的人可能会认为,要发挥想象力.创造力.....等各种"力"--这种方法的主要问题是:我们不是在进行纯粹的艺术创造,而是要最终满足客户需求,而不能天马行空. 有的人可能会想到,参考其它的系统吧,把类似系统拿过来改吧改吧 --这种方法的主要问题是:如果没有其它类似系统给你参考呢 ?还有的人干脆就说:拍脑袋吧,凭感觉吧 -- 这种方法的主要问题是:

连载:面向对象葵花宝典:思想、技巧与实践(28) - 设计原则:内聚&耦合

前面通过实例讲解了一个一环扣一环的面向对象的开发流程:用例模型 -> 领域模型 -> 设计模型(类模型 + 动态模型),解答了面向对象如何做的问题.接下来我们就要讲"如何做好面向对象设计"的技巧了 =================================================================== [内聚] 参考维基百科的解释,内聚的含义如下: cohesion refers to the degree to which the eleme

连载:面向对象葵花宝典:思想、技巧与实践(1) - 程序设计思想的发展

史前时代:面向机器 最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的指令和数据.简单来说,就是直接编写0和1的序列来代表程序语言.例如:使用0000 代表 加载(LOAD),0001 代表 存储(STORE)等.  机器语言由机器直接执行,速度快,但一个很明显的缺点就是:写起来实在是太困难了,一旦你发现自己写错了,改起来更蛋疼!这样直接导致程序编写效率十分低下,编写程序花费的时间往往是实际运行时间的几十倍或几百倍.  有一个关于机器语言和比尔盖茨的笑话,是说比尔

013_《Delphi面向对象编程思想》

<Delphi面向对象编程思想> Delphi 教程 系列书籍 (013) <Delphi面向对象编程思想> 网友(邦)整理 EMail: shuaihj@163.com 下载地址: Pdf 作者: 刘艺 [作译者介绍] 丛书名: Borland核心技术丛书 出版社:机械工业出版社 ISBN:7111127722 上架时间:2003-10-10 出版日期:2003 年9月 开本:16开 页码:476 版次:1-1 内容简介 这是一本纯粹讨论dlephi面向对象编程的力作. 本书以精

Silverlight游戏设计:(五)面向对象的思想塑造游戏对象

传说,面向对象的开发模式最初是因为程序员偷懒而不小心诞生的.发展至今,人们从最初的热忠于 讨论某某语言是否足够面向对象到现在开始更广泛的关注面向对象的思想而不是具体内容.面向对象的思 想其实并不深奥,它存在的目的只有一个:让程序开发更贴近我们的现实世界. 还记得猫.猫叫:狗.狗吃东西吗?无数的程序员都喜欢将此类似的情形设计当作面向对象最好的例 子.是的,非常生动且形象:但实际运用中你是否能真正做到举一反三? 回述到游戏设计中,大家是否时常会感觉游戏世界与我们的真实世界如此贴近?游戏中的精灵好比我

java语言学习002_面向对象编程思想

      人类在认识世界时,为了方便自己和智慧提升,很自然的对事物进行了分类.对世界进行了抽象,若把所有各个事物看做对象,纵观所有对象,这些对象具有各自的或共有的特征,并且又有共有的或各自的的能力,这样就可以对具有相同一些特征和一些能力的事物进行了归类.       比如,车,有汽车,火车他们都有哪些属性?                  汽车,特征:长度,颜色,速度,轮胎,载重,平面行走--能力:移动,载东西,--                  火车,特征:长度,颜色,速度,轮胎,载重

求助、面向对象的思想查找字符串中的数字

问题描述 要用面向对象的思想来查找字符串中的数字.实现判断某个字符是否位数字的方法如下:publicstaticboolgetNumeric(stringstr){boolb=false;string[]ArrayInt=newstring[]{"1","2","3","4","5","6","7","8","9","

将面向对象的思想带入TC

写TC貌似是很简单的工作,但当动手写的时候往往会出现,不知道写什么,又感觉有一堆的东西需要写,即使一个简单的日常也会觉得里面的逻辑非常复杂,然后就是晕得不知所向. 个人认为,写TC没有固定的模式,也没有唯一的答案,每个人的方式不同,习惯不同,TC中的如何分类归纳也就自然不相同.但目标是一致的,基本目标是覆盖需求.无盲区:加强目标是加深测试点,完善用户友好性等. 下面分享下我写TC的几种思路. 第一种思路--先对象,后流程 面向对象是在平常入门学习中 首先接触到的概念,它不仅仅存在于代码的编写中,

重温面向对象的思想——构造器和重载

1.this关键字 this表示这个对象的参考名称:例如this.age1=age2;表示将age2的值,赋值给这个对象的私有属性age1. 2. .重温面向对象的思想--构造器和重载 构造器:创建一个对象时,有时候需要对在实例化一个对象时,对这个对象进行初始化,这个时候我们就需要构造方法来进行这种初始化. 重载:当这种初始化需要按照不同的语境,不同的参数的构造器来进行初始化. 总结--方法的重载是多种构造器,用以完成不同的初始化. -注意:构造器==构造方法,两者一样 3.构造方法和自定义方法