设计模式是不是有点太「玄」了?

最近在看《设计模式解析-第二版》这本书,看的有点吃力,作者本身对设计模式也不是很迷信,还有些人用“一千个人中,有一千个哈姆雷特”形容设计模式,那到底有…
关注者
802
被浏览
271,235

141 个回答

这不是「玄」,这是「代码复杂度(complexity)」。时间复杂度影响运行速度,空间复杂度影响内存消耗,代码复杂度影响开发效率。开发效率包括编写新代码的效率,也包括阅读理解和维护老代码的效率。

这个代码复杂度问题是什么导致的?是编程语言本身的设计导致的。《设计模式》里面各种模式解决的问题,对于 C++ 以及相似的语言(如 Java、C# 等)尤其有效。因为使用这几门语言的人特别多,所以设计模式好像很普遍适用的样子。但如果换一门跟 C++ 非常不像的语言,例如 Haskell 和 OCaml 这种函数式语言,你会发现很多设计模式不适用。不适用的意思不是不能用,而是根本不需要用到,因为这些语言不存在某些问题。

用一个常见的比喻来解释:某些编程语言设计上导致的特性是钉子(问题),设计模式是锤子(解决方案)。看不懂《设计模式》,或者觉得设计模式太玄的人,是拿着锤子四处找钉子。

如果你处于这种状态,那意味着你还没意识到钉子的存在。问题的根源往往源自于你的复杂系统实战经验不足,没有掉坑里的体验,自然不会想要去把坑跟填了。你没有见过坑(问题),别人递给你一把铲子(解决方案),你肯定觉得这很玄。但你试过掉坑里了,你会二话不说接过铲子开始填坑。

再打一个比喻:另外一些编程语言的特性是螺丝钉。如果你习惯了使用锤子来钉钉子,你见到螺丝钉的感觉就会很奇怪,甚至觉得很不顺手,因为你的锤子无法把螺丝钉锤进墙里。但那些从来没见过锤子和钉子的人,可能看到螺丝钉后随手就把它拧紧了,发现这个过程非常地直观和自然。

这是设计模式备受攻击的一面。核心论点在于:为什么某些语言的设计要有坑?为什么要人手一把铲子?明明其它语言可以做到没有这些坑(但肯定会有另外一些不同的坑),为什么不可以把这些坑在语言上给抹掉,免得人人都要自带铲子?

从面试上看

这个如果从面试趋势来看,设计模式(Design Pattern)的确有点太玄太高深的嫌疑了。


早年面试时,亚马逊坚持考OOD,实际上就是简单版的Design Pattern,比如著名的设计停车场的class structure。到今天,一线大厂基本上没有面试Design Pattern的,全是System Design;只有二三线厂家还残存着一些OOD、Design Pattern面试。可见,Design Pattern的重要性在过去10年间大大下降了。


个人认为,首先互联网对设计模式需求的确不是非常大:各个Service之间本来就是互相独立的,完全通过request/response之间联系,所以分布式系统(Distributed System)的概念和联系更加重要,而每个模块其实体积并没想象那么大。


其次,我认为设计模式有一个悖论:工作中真懂设计模式有实际经验的人,相当少见,至少是Tech Lead级别及以上,这种人有一个录一个就对了,还需要面试?最怕的是这种人连跳槽都懒得。所以面试设计模式的,无论面试官还是被面试者,估计99%都没做过任何实际设计,绝大多数都是纸上谈兵、照本宣科。


你说系统设计也存在这个问题?的确,但现实在于,懂系统设计还是会给实际工作加分不少,但懂设计模式我没看出工作中有机会用太多。

从Scalability上看

系统设计中有个经典的Horizontal Scaling和Vertical Scaling。


前者就是说,东西太大太复杂,用更多的普通Server去并行解决;后者则是说,还是一台Server,但是有更大的CPU更多的Memory等。


很显然,互联网时代,Horizontal Scaling拥有无与伦比的优势。我个人认为,Horizontal Scaling也是符合社会现状和人性的:想培养一个“什么都懂”的精英软件工程师,要比培养10个“略懂”的软件工程师难不知道多少。


设计模式主要是解决类似Vertical Scaling的问题,大概意思就是:当软件和工程过于复杂时,应该如何构建才能保证易于维护拓展?但问题就来了——绝大多数情况下,为什么要让“软件和工程过于复杂”这种情况出现呢?为什么不在它们过于复杂之前,就适当重构、分解甚至分布式化呢?


我能想象到的场景,大概一个是单机游戏,一个是相对复杂的单机App,比如Excel等。这种情况设计模式的确很有用,但开发和维护成本都是相对于互联网较高的。


或者可以说,新兴的互联网,用Horizontal scaling做到了更高的整体效率和更低的开发周期,从而打败了Veritical Scaling的单机软件,导致了系统设计也同时打败了设计模式。

设计模式很有趣

这并不是说,设计模式没用,或是技术含量低。我记得我看过一个什么模式忘了,但专门服务于游戏的,非常有趣,比如同屏内有50个机枪兵(星际争霸),那么按照该设计模式,每个机枪兵不需要存太多信息,只要他们差异化的信息比如位置X、Y、残存HP、当前动作等即可,真正昂贵的那些比如绘图等详细信息都只存一个copy,以防资源浪费。


还有比如一个UI存在多个模块(Component),每个模块都可能更改共同的数据从而刷新其它UI Component,这时候就要用什么Event Aggregator Pattern,不在经典23种之内,但跟后端经典的Message Queue几乎同一个思想:都是用Subscriber和Publisher来发送、接收信号(可见前后端的很多思想也是共通的)。没有了这个Pattern,就等着各种乱七八糟的UI重复刷新吧。


设计模式实在是高深有趣,只是技能通用性不行,往往无用武之地。


当然,Singleton Pattern和Factory Pattern是唯一需要掌握的两个Pattern,这是基础知识,不算设计模式。背下来就好。