面向对象的设计模式(以下简称DP)是22年前GoF四位大师共同著述的,今天依然在设计中发挥重要的指导作用。
但是如果没有一定的实际开发经验与代码编写量,或者为了设计模式而设计模式,那么建议还是暂时不要管它。
建议从最简单的KISS原则开始,或者从一定的代码量后,追求可读性追求更高目标,可以先做一系列重命名提取方法等基础重构。之后如果仍然觉得代码依然缺乏优雅的特性,再考虑重构到设计模式。
总而言之,设计模式不应该生搬硬套塞进代码里,而是应该根据需要,从代码中自然生长出来。
作者 | 冰果
20年多前,软件设计领域有四位大师(GoF,Gang of Four,即Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides 俗称“四人帮”)。他们通过著述《设计模式:可复用面向对象软件的基础》这本经典之作,阐述了设计模式领域的开创性成果。
最近,在朋友圈看到朋友转发的一段马云的讲话。马云说:如果你发现你的朋友,长期做一件事,你观察他6个月,如果他还在做,你也刚好有需求,你就找他了解一下!如果他做了一年,还在做,说明这个事情肯定不错,你一定要找他好好了解一下!
如果他做了3年还在做,而且越做越好,越做越努力,说明这个事情是他的目标,你一定要跟他一起做。
如果他做了5年还是在做,而且不顾一切的做,说明这个就是他的生命,一个用生命做视野的人,你无论如何要跟上他,因为,只有跟上那些用生命做事业的人,才能带你去到比你想要去的更高的位置!因为如果不好,他早就不会做了,如果是骗子他也早都消失了!
看设计模式书有时候很无聊,我们不妨先来考察一下设计模式这本书的4位作者,结合一下马云的讲话,看看他们是不是『骗子』,是不是早就消失了,是不是搞了一个『设计模式』这个骗局之后就不干这一行当了。
下图中,4位作者站成一排的照片是在OOPSLA 大会上1994年拍的。下面的大头照是我从谷歌搜到的最新的照片,当年的大师也扛不住岁月这把杀猪刀啊。我们不按照书的作者顺序来,而是按照上面1994年拍的一张合影从左到右来。
首先是Ralph Johnson 博士,生于1955 年 10 月 7 日,现60 岁。他2015年在reddit上的留言道:
我从1985年到2012年都是CS教授,然后退休后开了一家公司,负责构建一种最终用户可以编程的会计系统。最爱的编程语言是Smalltalk,最近几年用Java和Groovy多。
1978年结婚,现在有3个小孩1个龟孙。其中有一个小孩当了码农。我觉得编程仍然是充满乐趣的事情,并且大部分时间都花在上面。
其次是Erich Gamma 博士,1961 年 3 月 13 日生于瑞士苏黎世,现55岁。与肯特·贝克共同创作了JUnit;两人也曾共同投入Eclipse的开发与软件架构设计。曾服务于IBM公司。2011年8月加入微软公司,负责Visual Studio Code的开发。从其github上的账号emamma来看,其开发提交活动依然非常活跃。
再次是Richard Helm博士,生辰不详。1988-1993年(5年)在IBM研究院Thomas J. Watson研究中心担任研究员。1993-1995年在DMR GROUP担任工程师。1995-2000年在IBM Consulting Group担任咨询师。2000-2002在Boston Consulting Group的子公司Platinion工作。
2002年5月至今在担任Boston Consulting Group的合作伙伴。根据其在领英的自我介绍,目前主要工作在于帮助客户利用最新技术提升他们的业务竞争力。
最后是John Vlissides博士,1961年8月2日生。1986年在斯坦福大学担任软件工程师、咨询师、研究学者。1991年起,在IBM研究院Thomas J. Watson研究中心担任研究员。 2005年11月24日感恩节在家中因脑癌去世。当时消息出时,全世界各地的程序员也为此感到震惊,因为时年仅44岁。
看完GoF的现况介绍,有种什么感觉呢?
什么? 感觉没有一位发财嘛!
对的,学设计模式,发不了财。想发财可能需要去研究研究商业模式而不是设计模式。如果想通过学设计模式发财的,还是绕路吧。
这么老了还在写代码?
对的,谁说写代码只能是30岁之前干的活。想30岁之后写代码写不下去了,打算转管理线或者转产品旺的,其实也不用着学设计模式,还是省省别费那个脑力,绕路走吧。Ralph都当爷爷了仍然还在写代码呢,这是一种什么情怀啊。
竟然没有出后续书籍?
对的,人家觉得这一本就是经典,其他的只能是锦上添花。况且相关锦上添花的书海了去了,其实没必要凑这个热闹。
竟然没有出来维护它?
对的,网上有一些言论说它过时了,说它太难了。人家说,设计本来就没那么容易的。20多年前的Small Talk语言是面向对象语言的鼻祖的地位依然没有动摇呢。计算机系统也依然是N年前冯诺依曼体系结构,并没有发生任何变化啊。
20年多年了,有人说设计模式陈旧过时了,有人说设计模式太难了。我们回过头来看看2009年有一个对GoF三作者的采访(采访详情,可以自己谷歌)时,Ralph说,大多数程序员都不是被聘请为编写一个可重用的软件,但是你必须知道一个可重用的软件是如何工作的,我们的模式是重用软件的通用方式,如今他们还是有用的。软件设计是难的,这正使它变得有趣,善于软件设计的人会从解决难问题中得到乐趣:将混乱变得秩序,克服困难。
从作者本身来说,他们并没有认为设计模式过时了,只是由于技术的进步,可能有些模式消失了或者变成一种隐性的存在,Ralph的话值得好好读上3遍。
有人说设计模式很好。错。设计模式其实是中性的,无所谓好坏。有些模式应用的较少一些,有一些模式在某些场景下还是反模式,比如Singleton。
有人说设计模式很复杂。错。有的模式其实非常简单,比如模板方法模式。有些比较复杂,比如访问者模式。平均而言,简单的模式比复杂的模式用的更多。
有人说小项目中没必要设计模式。多小的项目算小项目呢,其实只要经过良好的设计一个项目也可以不包含任何设计模式。但是也可能包含多个设计模式,但是跳过比较复杂的结构和行为模式,比如访问者模式或者责任链模式。
有人说使用设计模式需要熟练的开发人员。对于相对复杂的模式来说这个说法是部分成立的,但是绝对不是所有模式。
有人说使用设计模式会提升项目成本。不一定,如果设计模式使用的恰当的话。但是如果缺乏设计或者设计不良好,或者错误的(包括滥用)应用了设计模式,那肯定是会提升项目成本。
有人说设计模式会使得代码干净整洁。其实所有的代码都应该保持干净整洁,无论是否显式地应用了设计模式。 所以,设计模式不是万能的,它是中性的,不是所谓的灵丹妙药,如果不恰当的使用,反而会带来问题(比如设计臭味)。
这个可比设计模式简单多了 !
翻一遍设计模式的书,很多人就开始晕倒了。怎么一个个模式看UML类图,怎么那么像啊,Proxy模式与Docorater模式等简直就是没有二样。
嗯,确实是这样子的,我当初初学设计模式时,实际上也是这种感受。只是为了给别人讲解设计模式,我是硬着头皮再看第二遍第三遍……
所以,从我的经验出发,如果你不是为了给别人去讲设计模式,那么可以暂时把它放在一边,先学一个简单的原则吧,它叫做KISS。
对,就是大写的KISS。小写的kiss那是小爱,大写的KISS才是大爱。什么工厂方法模式抽象工厂模式,太过复杂,为啥不直接new一个对象呢,你看多简单。
什么?还不知道什么叫KISS?那就赶紧查查看吧,其实,很简单的,http://www.acronymfinder.com/KISS.html 。
KISS就是Keep It Simple & Stupid、Keep It Slim & Sexy、Keep It Short & Safe、Keep It Silly & Sound、Keep It Simple, Spiritually等,这些简单四级单词还给英语老师他老人家也不收的。
再看看Unix哲学:小即是美、让每一个程序只做好一件事情、尽快建立原型、舍高效率而取可移植性、使用纯文本文件来存储数据……
实践上怎么玩KISS呢,首先你得从源头上下手,客户和产品旺经常提的需求除了干什么外,还经常夹带私货,就是要求你“怎么干”。
如果你觉得需求有问题,可以义正言辞的“拒绝”之,给他指出个一二三,让他们先好好想去,说不定想想就没了呢。
如果夹带了还要求你怎么干时,此时你可不能被牵着鼻子走。怎么干是实现的事,码农应该最有发言权了,我们此时应该开动脑筋,设计出最简单的解决方案。
简单的方案一般是恰到好处地实现了当前的需求,逻辑清晰结构简单,没有多余的肥肉,能快速地编码测试并上线。
举个栗子,某个需求,你原始用1000行代码搞定了,但是经过Code Review一下之后,KILL掉其中的800多行,还剩200行不到,这就是一种KISS的体现。
写简单少量的代码,不但花费的时间少错误少,而且修改起来也容易。
再举个栗子,又某个需求,是要求增加一个替身登录的功能,这样子就可以披着别人的『羊皮』却以自己的用户名密码登录进系统,使用替身角色的做一些事情。
常见的做法,是新增一个特定登录入口界面,里面除了输入自己的用户名密码之外,还要求选择具体『羊皮』,以确定是作为谁的替身进入系统。KISS一点的做法,那就是不新增页面,已有登录页面也不改动,只是在用户名输入栏中使用『用户名@替身』来完成实际替身的选择工作。
有这么一个常数叫Norris常数,说的是一个未经培训的码农在他遇到瓶颈之前能写出的平均代码量大概是2000行。
超过之后,代码会变得混乱不堪,以至于本人都无法轻松地进行调试和维护。
什么?你写的有效代码还在2000行以下,你就想折腾设计模式了,我建议你还是先攒点代码量吧!
这就好比,你最多就跑过5公里,突然有一天,你心血来潮觉得跑马拉松很时髦,就找了个名额去也去试一把一样,如果摈弃天赋之外,基本上结果就是会“死的”比较惨。
什么?你只是觉得完成日常工作就OK了,代码刚写完能跑就OK了,自己的代码除了找BUG没办法多看上一眼之外,根本不想看第二眼第三眼的话,我也建议你别扯什么设计模式了。
设计模式是给那些对代码有追求的人准备的。每一行代码对于有追求的码农来说,都是一行现代诗的诗句;每一段代码,都是在叙述一个不一样的故事。
如果你很努力,代码量很快就到达了2K了,是不是就要找一本设计模式的书来看看看呢?
我很负责任的告诉你,此时,你需要找的是一本重构的书,而不是设计模式的书。先学学重构,把命名搞的有意义,把函数拆的小一点,把风格写的好看一些。等这些都搞定了,再来玩设计模式吧,然后就可以直接高级重构到模式了。
说了这么多,还挡不住你学设计模式的热情,那么建议你就从一个小目标开始吧,比如先学策略模式和模板方法模式。
这里就不展开讲这两个模式了,只是提醒一下,策略模式的意图是与算法相关的。 比如算命,有人喜欢相面有人喜欢相手有人喜欢看八字,这就是不同的算法。
模板方法模式是与套路相关的,比如追妹三步曲,第一步引起注意第二步聊上第三步牵上,这都是套路,但是对于南方妹纸和北方汉纸,可能具体的方式不一样,那就可以有两套具体的模板:南方追妹纸具体模板和北方追汉纸具体模板,都继承自追妹的抽象模板。
但是网上所有的讲解设计模式的例子,基本上都有一个问题,那就是为了设计模式而设计模式。你可以看到一个父类下面两个不同的子类,实现都是一两句话的内容。
如果实际开发中也这么使用的话,基本上又命中了另外一种代码坏味『懒惰类』,就是一个类干的活太少了太瘦了,不足以称之为一个『类』了。
一个类应该有一定的体型,不胖不瘦才是最好,胖了就要分拆,瘦了可能就需要合并。所以真正的码农都是有某种『洁癖』的。
总而言之,对于缺乏实际编码经验,或者代码量写得太少的童鞋们,建议是先不要碰设计模式了。
如果为了应付面试,或者想先大致了解以方便吹牛,那么就从简单的模式开始吧,首先理解其意图任然是最重要的事情。
最后一句话,设计模式应该从代码中自然生长出来,而不是你强制添加上去的。意味着,常见设计模式的应用,一般都是通过持续重构来获得。