更简单实用的设计原则
# 更简单实用的设计原则
七大设计原则是一种理想环境下的设计原则。在实际的项目开发过程中,往往没有这么充分的条件(如团队成员的整体技术水平、团队的沟通成本),或没有这么充足的时间遵循这些原则去设计,或遵循这些原则设计的实现成本太大。在受现实条件限制不能遵循七大原则来设计时,我们还可以遵循下面这些更为简单、实用的原则,让我们的程序更加灵活、更易于理解。
# KISS原则
Keep It Simple and Stupid.
保持简单和愚蠢。这一原则正如这句话本身一样容易理解。“简单”就是要让你的程序能简单、快速地被实现;“愚蠢”是说你的设计要简单到傻瓜都能理解!
为什么要简单呢?因为大多数技术团队,成员的技术水平都参差不齐。如果你的程序设计得太复杂,有些成员可能无法理解这种设计的真实意图,而且复杂的程序讲解起来也会增加沟通成本。为什么说愚蠢呢?对有同样需求的一个软件,每个人都有自己独特的思维逻辑和实现方式,因此你写的程序对于另一个人来说就是个陌生的项目。所以你的代码要愚蠢到不管是什么时候,不管是谁来接手这个项目,都能很容易地被看懂。
这个原则其实在警醒我们不要过度设计!有些人学了一些设计模式,觉得设计模式很高大上,就为了模式而模式,去过度地设计程序,这是非常不可取的。一旦陷入过度设计的泥潭,排查问题的时候会更困难,很容易"前人挖坑,后人遭殃"。
# DRY原则
Don't repeat yourself.
不要重复自己。这个原则的意思也很简单:不要重复你的代码,要尽可能地提高代码的复用率。即多次遇到同样的问题,应该抽象出一个共同的解决方法,不要重复开发同样的功能。
要遵循DRY原则,实现的方式非常多:
- 函数级别的封装:把一些经常使用的、重复出现的功能封装成一个通用的函数。
- 类级别的抽象:把具有相似功能或行为的类进行抽象,抽象出一个基类,并把这几个类都有的方法提到基类去实现。
- 泛型设计:Java中可使用泛型,以实现通用功能类对多种数据类型的支持;C++中可以使用类模板的方式,或宏定义的方式;Python中可以使用装饰器来消除冗余的代码。
DRY原则在单人开发时比较容易遵守和实现,但在团队开发时不太容易做好,特别是对于大团队的项目,它考验着团队内的沟通。比如Tony在做模块A时用到了一个查询用户信息的功能,于是实现了一个getUserInfo(uid)方法;这时团队内的另一同事Frank在做模块B时,也要用到一个查询用户信息的功能,但他不知道Tony已经实现了这个功能,于是又写了一个getUser(uid)方法。即使双方都认为自己没有重复代码,但是就对整个软件工程来说是冗余了。
# YAGNI原则
You aren't gonna need it,don't implement something until it is necessary.
你没必要那么着急,不要给你的类实现过多的功能,直到你需要它的时候再去实现。这个原则简而言之:只考虑和设计必需的功能,避免过度设计。
软件开发首先是一场沟通博弈。它背后的指导思想就是尽可能快、尽可能简单地让软件运行起来(do the simplest thing that could possibly work.)。只实现目前需要的功能,在以后需要更多功能时,可以再进行添加。如无必要,勿增加复杂性。
# ROT原则
“Rule of three”称为“三次法则”,指的是当某个功能第三次出现时,再进行抽象化,即事不过三,三则重构。
这个法则表达的意思是:
- 第一次实现一个功能时,尽管大胆去做;
- 第二次做类似的功能设计时会产生反感,但是还得去做;
- 第三次还要实现类似的功能做同样的事情时,就应该去审视是否有必要做这些重复劳动了,这个时候应该重构代码了,即把重复或相似功能的代码进行抽象,封装成一个通用的模块或接口。
这样做有几个理由:
- 省事。如果一个功能只有一到两个地方会用到,就不需要在“抽象化”上面耗费时间了。
- 容易发现模式。“抽象化”需要找到问题的模式(即共同点或相似点),问题出现的场合越多,就越容易看出模式,从而更准确地“抽象化”。
- 防止过度冗余。如果相同功能的代码重复出现,后期的维护将会非常麻烦,这也就是重构的意义所在。
到这时,你会发现DRY原则、YAGNI原则、三次法则之间有一些非常有意思的关系。DRY原则告诉我们不要有重复的代码,要对重复的功能进行抽象,找到通用的解决方法。YAGNI原则追求“快和省”,意味着不要把精力放在抽象化上面,因为很可能“你不会需要它”。这两个原则看起来是有一些矛盾的,这时就需要三次法则来进行调和,寻找代码冗余和开发成本的平衡点。三次法则告诉我们什么时候可以容忍代码的冗余,什么时候需要进行重构。
# CQS原则
命令查询分离原则(Command Query Separation),引入了两个方法性质:
命令(Command):当一个方法要改变对象的状态的时候,它就具有命令的性质。
查询(Query):当一个方法返回一个值来回应一个问题的时候,它就具有查询的性质;
通常情况下,一个方法可能是单纯的查询模式或者是单纯的命令模式,也可能是两者的混合体。我们在设计接口时,应该尽量使接口单一化(方法级别的单一职责原则),保证方法的行为是命令或者查询。这样的好处是查询方法不会改变对象的状态,没有副作用;而会改变对象的状态的方法不可能有返回值。
CQS原则在实际应用中应当视实际情况而定,需要权衡语义的清晰性和使用的简单性。在功能交互上,将Command和Query功能合并入一个方法,方便了客户的使用,但是降低了清晰性。而在后端接口设计时候,在一个接口中,就尽量不要既有查数据又有更新数据的操作。在系统设计中,很多系统也是以这样的原则去设计的(如数据库的主从架构),查询功能和命令功能的系统分离,有利于提高系统的性能,也有利于增强系统的安全性。
摘自: 罗伟富. 《人人都懂设计模式:从生活中领悟设计模式:Python实现》. 电子工业出版社