反模式:神仙大类和黄金大锤

来自:码农翻身(微信号:coderising),作者:冰果

数学中有正数和负数


物理学有『物质』和『反物质』的存在


武侠小说中有九阳神功也有九阴真经


生活中有婚姻也有出轨


......


事物总是充满这种相互矛盾而统一的有趣现象。


对于GoF提出的23种设计模式,是否也有反模式呢?答案是显而易见的。


一个设计模式在特定的场合下是积极并且显现优势的,但是在偏离最佳适合场景下,它本身就会转变为了一个反模式,从而导致不良的影响,就像现实世界中没有所谓的纯粹的好人或者坏人一样。


反模式


Andrew Koenig在1995年首创了anti-pattern这个词,三年后anti-pattern因《AntiPatterns》这本书而获得普及,而它的使用也从软件设计领域逐渐扩展到了日常的社会互动中。


反模式其实体现的是一种积极反思的行为,通过对不断出现,糟糕透顶的解决方案反思之后的深刻总结。让我们能够从错误或者失败中学习提高,避免犯相同的或者类似的问题,提升效率。理解了反模式,有助于我们在实际工作中预防或者改正它们。


有一篇文章,讲到用了5种设计模式来完成一个Hello Word的打印,使用关键字「write Hello Word with design patterns」谷歌一下就能找到(请使用正确的姿势访问谷歌),甚是有趣,然而有趣的背后反思,却是『为了设计模式而设计模式』,成了一种典型的反模式「为了XX而XX」。


从图书网站上,也可以搜索到一些反模式的书籍,比如测试反模式,SQL反模式,Python反模式等,连最近很火的微服务也有了反模式,这些书中都总结了一些最差实践,让我们学习并避免之。



反模式有很多种,我这里想给大家介绍其中的两种,分别是神仙大类黄金大锤,我这里把他们比喻成倚天剑和屠龙刀,意思是这种大杀器一般要谨慎使用,因为威力太大,用得不好的话,就极有可能伤及自身,或者没有伤到自身,伤到边上无辜的花花草草也是不好的。


神仙大类


神仙大类,又称God Class, Blob Class等,就是一个类拥有太多属性和方法(比如超过20个),它能处理的事务涉及方方面面(比如员工类,涉及工资计算、税务计算、入职离职、数据库读写、请假报销等等),它所占用的代码行数从数百到上万行。


「神仙大类」是KISS原则和SRP原则的反模式。


我自己虽然未曾有幸见识过上万行的大类(倒是听说过不少),但是确实亲自见证过超过2000行的只有一个main函数的大类。


针对这种大类,我是该献上我的膝盖还是我的口水呢,我想刚开始是膝盖,因为不觉明历,后来铁定就是WTF口水了,因为我不幸接手了并负责维护它,搞得每次只要一改它,在上线的时候我都会心惊胆战,晚上睡不好觉。


当然,对于一锤子买卖,不再需要维护的代码,或者需求绝对不会变更的代码,这种神仙大类就让它逍遥去吧。


唯一的不足之处就是,不能为下一个项目提供可复用的单元,只能看着年龄在增长,技能和效率却没有什么提升了。


普通程序员只是年复一年地完成日常的业务需求,没什么代码复用可言,好的程序员却可以在完成日常业务开发的同时,不断地总结并丰富自己的代码工具箱,代码复用率很高,真正需要写的业务代码也写得非常少,有时候只需要做一下配置,就可以完成类似的事情。


有一种声音,就是神仙大类的拥趸说,你看,我一个大功能就一个大类搞定了,一个大类就一个文件,如果按照你的那套所谓的SRP/KISS,至少要不下20个类的小文件了,我不也算符合简单化原则了啊,一个文件还不算简单嘛。


乍一听,我竟无言以对,如果你一个类文件里面也是分了各种层次,做了各种不同抽象设计的话,好像也不无道理。只是,这种情况下,一个文件里面那么多功能,如果想重用其中的一个,咋个办呢,是不是得把整个大类照单全收,还是把要重用的那个小函数拷贝一份出来?


只是同一段代码一旦重复拷贝,就违反了DRY(Don’t Repeat Yourself )干燥不惨水原则,而被 WET(Write Everything Twice)湿漉漉反模式给恨恨地砸脸了。


神仙大类,本质上就是一个『集大成』的大胖子,在这个以瘦为美以减肥为时尚的今天,确实不受欢迎,感情好的时候说胖子是潜力股还亲切地喊小胖胖,感情破裂了转口就骂人家死胖子了。


你虽然不能像林丹那样拥有拥有8块完美腹肌,但是你可以让你的代码做到啊,只需要远离神仙大类,或者使用『人挡杀人佛挡杀佛』的重构「拆」字诀把遇到的神仙大类就地拆成大约8个各司其职的小类就可以了。



黄金大锤


黄金大锤,Golden Hammer,指使用相同的工具、产品或技术,解决几乎所有的问题。


如果你只有一个关系型数据库,那么任何问题都看上去是其中的一张关系表。或者我们学习了设计模式,然后就开始肆无忌惮地到处用设计模式,就连最简单的打印一个Hello World的入门程序也都能用上几个设计模式的话,那就是把设计模式当成黄金大锤了。



有一种『面向接口编程』滥用的反模式,就是『一个服务一个接口』。这种常见的就是所有的服务类都有一个所谓的XxxService及XxxServiceImpl,前者是一个接口,后者是对应的惟一实现。


问题的关键在于,这种XxxService和XxxServiceImpl竟然一一对应,也就是说一个XxxService其实只有一个XxxServiceImpl与其对应。


这如果不是对『面向接口编程』的一种曲解与滥用,那就是『夸夸其谈的未来性(Speculative Generality)』的代码坏味。


『接口』在面向对象的设计中,是属于抽象层面的东西,那什么时候需要抽象呢?一定是两种及以上事物拥有共同的一些特征时,才能形成抽象(自底向上),或者从高层定义一些抽象特征,由两种或以上事物来体现这个特州,这种抽象才有意义(自顶向下)。


比如光喊我一个人吃饭,你根本不需要抽象,喊我的名字我就来了(我的思路是,吃饭不积极肯定有问题

来自:码农翻身(微信号:coderising)

作者:刘欣

码农翻身.jpg

推荐↓↓↓
Java编程
上一篇:用简单代码实现IOC容器 下一篇:面试问你为什么要用Spring怎么答