谈起《设计模式》,那是几乎无人不知,无人不晓,大名鼎鼎的GoF的惊世之作,真是“平生不识GoF,学尽设计也枉然”!

然而,设计模式真的是软件设计的“瑞士军刀”,切、削、锯、钻样样精通吗?

读过《设计模式》的读者估计不少,但真正注意过《设计模式》的副标题的估计很少,而这个副标题却是避免误解设计模式的关键。《设计模式》的副标题是:可复用面向对象软件的基础!

不要小看了这短短的一句话,如果你没有看这句话,或者只是一扫而过并没有仔细体会,那么你很可能就认为设计模式是一把“瑞士军刀”,能够解决所有的设计问题;而实际上“设计模式只是一把锤子”,有句谚语叫作“如果你手里有一把锤子,那么所有的问题都变成了钉子”,如果你拿着设计模式这把锤子到处去敲,要么东西被敲坏,要么就不起作用。

为什么说设计模式只是一把锤子呢?我们还是从副标题来看。《设计模式》的副标题揭示了设计模式的两个主要约束。

  • 设计模式解决的是“可复用”的设计问题
  • 设计模式应用的领域是“面向对象”

相信经过我这么一提醒,大家基本上都能够明白了为什么说“设计模式只是一把锤子”了。

设计模式只能解决“可复用”的设计问题,其他的例如性能设计、可靠性设计、安全性设计、可服务性设计等都不是设计模式能够解决的;

设计模式只是在面向对象的语言中应用,如果是非面向对象的语言,那么就不怎么好用了。当然,你可以在C语言中应用设计模式,但毕竟要有不少折腾,用起来也不那么得心应手。

所以,当你遇到一个问题就想到设计模式的时候,一定要注意“设计模式只是一把锤子”,不要拿着这把锤子到处去敲!

本文选自李运华老师新作《编程的逻辑:如何用面向对象方法实现复杂业务需求》,本书会通俗易懂地带你揭示面向对象的本质,助你实现复杂的业务需求!

知易行难,设计模式应用的问题

形而上者谓之道,形而下者谓之器。
——《易经·系辞》

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

一个典型的现象是:

很多人能够熟练背诵出所有的设计模式,能够快速画出各种设计模式的UML类图,也能够熟练地写出《设计模式》一书中各个模式的样例代码。

但一到实际的项目设计和开发的时候,往往都会陷入迷茫:要么无从下手,不知道哪个地方要用设计模式;要么生搬硬套,胡乱使用设计模式,将方案和代码搞得一团乱麻。

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

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

学习《设计模式》一书中的23个设计模式,只是掌握了设计模式的“器”,但并没有掌握设计模式的“道”。就像一个工匠,锯、钻、锤、刨样样精通,但如果不知道在什么地方该用锯,在什么地方该用钻,那么他肯定是一个不合格的工匠。

为了能够更好地学习和应用设计模式,我们也需要掌握设计模式的“道”。

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

拨云见日,寻找设计模式之道

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

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


在遇到以下情况时使用Facade模式。

  • 当你要为一个复杂子系统提供一个简单接口时,子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类,这使得子系统更具可重用性,也更容易对子系统进行定制。但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的默认视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。

  • 客户程序与抽象类的实现部分之间存在着很大的依赖性,引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。

  • 当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,则可以让它们仅通过Facade进行通信,从而简化了它们之间的依赖关系。


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

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

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

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

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

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

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

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

设计模式之道就隐藏在“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”的问题。

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

答案很明显:变化不好!

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

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

  • 客户给你提了新需求,你不做,能拿到合同吗……
  • 行业正在兴起新的流行功能,你不做,你的系统有人用吗……
  • 一项创新带来了新的机遇,你不做,能抢占市场吗……

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

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

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

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

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

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

举一反三,活学活用设计模式之道

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

例如:

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

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

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

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

(完)

面向对象经过几十年的发展,理论已经趋于成熟。虽然面向对象更加类似于“人的思想”,但其理论相比面向过程来说要复杂很多,相关的知识和技术也更加纷繁复杂。

因此导致很多人在学习面向对象的时候感觉比较难,或是在实际开发中不能很好地运用这些技术。

这本《编程的逻辑:如何用面向对象方法实现复杂业务需求》是李运华老师在多年的摸索与不断的实践下,逐渐形成的一套完整的面向对象方法论。本书可以帮助更多的程序员更好地掌握面向对象思想和技巧,享受程序人生,实现自己的梦想!

李运华 著

设计模式只是一把锤子,不要拿着到处去敲!相关推荐

  1. 海尔“灯塔”张瑞敏,一把锤子砸出的硬核人生

    本文概要:执掌海尔集团37年后,今年73岁的张瑞敏决定不再参与新董事提名,正式交棒.在他的"颠覆"下,海尔从当年濒临破产的烂厂子,如今成为闻名全球的世界级中国造,海尔如今更是成为了 ...

  2. 【51单片机】室友用一把王者时间,学会了去使用数码管。

    ♐ 写在前面

  3. 世界那么大,我们一起到处去看看

    6月26日 华为云骑行中国从深圳启程 从惠州到汕头 从叶挺将军故居到闽粤南澳总镇府 从水库的绿道到村庄的小路 沿途美丽风景如画 有信仰的云相伴骑行路 和小编一起回顾下 那些大汗淋漓却值得骄傲的美好回忆 ...

  4. 于冰:用户导向的音视频体验优化

    在LiveVideoStackCon2018音视频技术大会上,快手音视频技术负责人于冰分享了题为<用户导向的音视频体验优化>的主题演讲,从用户的角度来去谈音视频的体验优化. 文 / 于冰 ...

  5. 领域驱动设计 (DDD)实例分析

    本文结合实例来分析下领域驱动设计 (DDD) 文章目录 啥是DDD 啥是驱动 DDD误解 啥时候用 啥是复杂 具体解决啥 为啥会耦合 咋解决耦合 咋做分治 咋做分界 模块 分层 咋落地 本文小结 啥是 ...

  6. 编程的逻辑-用面向对象方法实现复杂业务需求

    虽然不少同学一直在使用面向对象的语言进行项目开发,但是在分析.设计和编码过程中不一定用是真正的OOA/OOD/OOP的思想,贫血模型由于快速高效易上手,使用的项目不在少数,而随着软件规模和业务复杂度的 ...

  7. 学python是看书还是看视频-学 Python 你觉得是看书还是看视频?

    大家好,这是首发在我公众号「Python空间」的第 87 篇文章,想看更多的文章或者加我欢迎关注,我们一起交流. 今天有个新关注的读者在后台问了这么一个问题:"我准备开始学 Python,是 ...

  8. 另外五个 PHP 设计模式

    2019独角兽企业重金招聘Python工程师标准>>> 设计模式 一书介绍了很多此类概念.当时,我还在学习面向对象 (OO),因此我发现那本书中有许多概念都很难领会.但是,随着越来越 ...

  9. 微服务软件架构的认识和设计模式

    什么是微服务? 微服务存在多种定义. 如果搜索 Internet,会发现许多有用的资源,这些资源提供了自己的观点和定义. 但在微服务的以下大部分特性上,已广泛达成共识: 封装客户方案或业务方案. 你要 ...

最新文章

  1. SpringMVC源码系列:HandlerMapping
  2. 《压缩感知理论及其研究进展》读书笔记
  3. swiper 定义放多少张图片,小程序swiper轮播图,自定义样式,两种方法:原生方法和bindchange方法;将点点改为数字(当前第几张 /总共几张);点击点点跳转当前图片...
  4. linux mysql数据库优化_MySQL_Linux下MySQL数据库性能调优方法,以下的环境具备一定的代表性 - phpStudy...
  5. 高德地图区域线显示_护航国庆假期,助力重点区域精细化管理——扬州交警与高德地图联合推出“全境智能”系统...
  6. JavaScript 数组 API 全解析
  7. matlab mcc 安装,matlab中安装mcc
  8. 获取当前周和前一周周一和周天,下一周周一和周天
  9. 【Hive】数据导入方法
  10. Javascript:拦截所有AJAX调用,重点处理服务器异常
  11. jenkins2 pipeline高级
  12. mysql 测试快生产慢_兴奋!阿里三位扫地憎专家总结的Mysql性能优化金字塔法则,操作细节满分...
  13. 局域网助手_IP地址管理和局域网远程助手
  14. Java 完全自学手册,从外包到大厂,再到年薪 100 万技术大佬都靠它
  15. 14.Excel vba开发-随机点名
  16. java 金字塔 2的幂_三角形数(金字塔三角形数量公式)
  17. 观点 | 滴滴 AI Labs 负责人叶杰平教授:深度强化学习在滴滴的探索与实践+关于滴滴智能调度的分析和思考+滴滴派单和Uber派单对比
  18. 超越之MongDB系列教程(六) MongDB的查询
  19. python3必应壁纸爬虫练手
  20. 教你1分钟学会贴iPhone钢化膜

热门文章

  1. 2)美国佬与才女薛涛的共同点
  2. 关于mac上如何U盘
  3. dva开源项目_后台前端管理系统,基于react、typescript、antd、dva及一些特别优秀的开源库实现...
  4. 用Python计算利率,告诉你亏了多少!
  5. redit高可用持久
  6. 两部苹果手机同步照片_安卓手机里的便签怎么导到苹果手机?安卓和苹果手机便签同步...
  7. 教你如何做好微信客户管理?做到这3点,效率翻5倍
  8. 【CP2K教程(二)】WO3的投影态密度和能带结构
  9. 无需编程,DIY自己智能小车的Android蓝牙遥控软件(三)
  10. 庄子 君子之交淡如水,小人之交甘若醴。