设计模式专栏: http://t.csdnimg.cn/4Mt4u
编程技巧专栏:http://t.csdnimg.cn/Ynuj9
目录
1.引言
我们常说,一定要重视代码质量,写代码之前,不要忽略代码设计环节。实际上,不做代码设计不好,过度设计也不好。在作者过往的工作经历中,遇到过很多同事,特别是开发经验比较少的同事,喜欢对代码进行过度设计,滥用设计模式。在开始编写代码之前,他们会花很长时间进行代码设计。对于简单的需求或简单的代码,他们经常会在开发过程中应用各种设计模式,希望代码更加灵活,为未来的扩展打好基础,实则过度设计,因为未来的需求并不一定会实现,这样做徒增代码的复杂度。因此,我们有必要讲一下如何避免过度设计,特别是如何避免滥用设计模式(面向对象编程范式、设计原则、代码规范和重构技巧等不容易被过度使用)。
2.代码设计的初衷是提高代码质量
谈到创业,我们经常听到一个词:初心。"初心"的意思是我们到底为什么做这件事。无论产品经过多少次迭代、转变多少次方向,"初心"一般不会改变。当我们在为产品该不该转型、该不该实现某个功能犹豫不决时,想想我们创业时的初心,自然就有答案了。
实际上,应用设计模式时也是如此。设计模式只是方法,应用它的最终目的(也就是初心)是提高代码的质量,也就是提高代码的可读性、可扩展性和可维护性等。所有的代码设计都是围绕这个初心来进行的。
因此,在进行代码设计时,我们一定要先思考一下为什么要这样设计,为什么要应用这种设计模式,以及这样做是否能够真正提高代码质量,能够提高代码哪些方面的质量。如果自己很难想清楚这些问题,或者给出的理由比较牵强,那么基本上可以断定这是一种过度设计,是"为了设计而设计"。
3.代码设计的原则是"先有问题,后有方案"
如果我们把代码看作产品,那么,在做产品时,我们就要先思考产品的"痛点"在哪里用户的真正需求是什么,然后开发满足需求的功能,而不是先实现一个"花哨"的功能,再东拼西凑出一个需求。
代码设计与此类似。我们先分析代码存在的"痛点",如可读性不高、可扩展性不高等,再有针对性地利用设计模式、设计原则对代码进行改善,而不是见到某个场景之后,就盲目地认为与之前看到的某个设计模式、设计原则的应用场景相似,随意套用,不考虑是否合适。如果有人起,就找几个伪需求进行搪塞,如提高了代码的扩展性、满足开闭原则等,这样是不可取的。
实际上,很多没有太多开发经验的新手,往往在学完设计模式之后会非常"学生气",不懂得具体问题具体分析,手里拿着锤子,看哪个都是钉子,不分青红皂白,套用各种设计式。写完之后,看着自己写的很复杂的代码,还沾沾自喜,这样的做法很不可取。希望本节内容能够给读者带来一些启发。
4.代码设计的应用场景是复杂代码
一些设计模式图书会给出一些简单的例子,但这些例子仅仅是为了能在有限的篇幅内向读者讲清楚设计模式的原理和实现,并没有实战意义。而有些读者会误以为这些简单的例子就是这些设计模式的典型应用场景,经常照葫芦画,盲目地应用到自己的项目中,用复杂的设计模式去解决简单的问题。在作者看来,这是很多初学者在学完设计模式之后,在项目中进行过度设计的首要原因。
应用设计模式的目的是解耦,也就是利用更好的代码结构,将一大段代码拆分成职责单一的"小"类,让代码满足"高内聚,低耦合"等特性。创建型设计模式是将创建代码和使用代码解耦,结构型设计模式是将不同的功能代码解耦,行为型设计模式是将不同的行为代码解耦。而解耦的主要目的是应对代码的复杂性问题。也就是说,设计模式是为了解决复杂代码问题而产生的。如果我们开发的代码不复杂,那么就没有必要引入复杂的设计模式。这与数据结构和算法应对的是大规模数据的问题类似。如果数据规模很小,那么再高效的数据结构和算法也发挥不了太大作用。例如,对几十个字符长度的字符串进行匹配,使用简单的朴素字符串匹配算法即可,没有必要使用具备更高性能的KMP算法,因为KMP算法尽管在性能上比朴素字符串匹配算法高一个量级,但算法本身的复杂度也高很多。
对于复杂代码,如项目的代码量大、开发周期长、参与开发的人员多,我们在前期要多点时间在设计上。代码越复杂,我们花在设计上的时间就越多。不仅如此,对于每次提交的代码,我们都要保证质量,以及经过足够的思考和精心设计,这样才能避免出现"烂代码效应(每次提交的代码的质量都不高,累积起来,整个目最终的代码质量就会很差)。如果我们参与的只是一个简单的项目,代码盘不大,开发人员也不多,那么,简单的问题用简单的解决方案处理即可,不必引入复杂的设计模式,不要将简单问题复杂化。
5.持续重构可有效避免过度设计
我们知道,应用设计模式可以提高代码的可扩展性,但同时会降低代码的可读性。一旦我们引入某个复杂的设计,之后即便在很长一段时间都没有扩展的需求,也不可能将这个复杂的设计删除,整个团队要一直背负着这个复杂的设计前行。
为了避免错误的需求预判导致的过度设计,作者推荐持续重构的开发方法。持续重构不仅是保证代码质量的重要手段,也是避免过度设计的有效方法。在真正有痛点时,我们再考虑用设计模式来解决,而不是一开始就为不一定实现的未来需求而应用设计模式。当对是否应用某种设计模式模棱两可时,我们可以思考一下,如果暂时不用这种设计模式,随着代码的演进,当某一天不得不去使用它时,需要改动的代码是否很多。如果不是,那么能不用就不用,遵守KISS 原则。对于 10万行以内的代码,如果团队成员稳定,对代码及的业务熟悉,那么,即便将所有的代码重写,也不会花费太多时间,因此,不必为代码的护展性过度担忧。
6.不要脱离具体的场景谈代码设计
代码设计是一个很主观的事情。毫不夸张地讲,代码设计可以称为一种"艺术"。因此,代码设计的好坏很难评判。如果真的要进行评判,那么尽量将其放到具体的场景中。作者认为,脱离具体的场景谈论代码设计是否合理是空谈。这就像我们经常说的,脱离业务谈架构是不切实际的。
例如,一个手机游戏项目是否能被市场接受,往往非常不确定。很多手机游戏开发出来之后,市场反馈很差,立即就被放弃了。另外,尽快推出并占领市场是手机游戏致胜的关键。所以,对于一些手机游戏项目的开发,前期往往不会在代码设计、代码质量上花费太多时间。但是,如果我们开发的是MMORPG(大型多人在线角色扮演游戏)类的大型端游,那么资金和人力投资相当大,项目推倒重来的成本很大。这个时候,代码的质量就很重要了。因此,在项目前期,我们就要多花点时间在代码设计上,否则,代码质量太差,bug太多,后期将无法维护,也会导致很多用户放弃而选择同类型的其他游戏。
又如,如果我们开发的是偏底层的、框架类的、通用的代码,代码质量就比较重要,因为旦出现问题或代码需要改动,影响面会比较大。如果我们开发的是业务系统或不需要长期维护的项目,那么放低对代码质量的要求是可以接受的,因为自己开发的项目的代码与其他项目没有太多耦合,即便出现问题,影响也不大。在学习代码设计时,我们要重视分析问题能力和解决问题能力的锻炼。在看到某段代码时,我们要能够分析代码的优秀之处和不足之处并说明原因,还需要知道如何改善代码。相反,如果我们只是掌握了理论知识,即便把22种设计模式的原理和代码实现背得滚瓜烂熟如果不具备具体问题具体分析的能力,那么,在面对多种多样的真实项目的代码时,也很容易滥用设计模式而过度设计。
7.总结
总之,避免过度设计需要保持清晰的目标、关注用户需求、简化设计、避免过早优化,并持续学习和改进。通过遵循这些原则和建议,你可以有效地避免过度设计,提高项目的成功率和效率。