什么是设计原则?

设计原则是一组指引,使用他们可以避免不良的设计,不良的设计通常有以下几点特性:

  • 刻板 - 很难迎合变化,每个变化都会影响到系统中其他的部分.
  • 易崩溃 - 当你修改了系统,会导致系统中其他(非预期的)部分崩溃.
  • 无法复用 - 代码无法用在其他系统,因为它们无法从当前系统中抽取出来.

接下来,我们就看看有哪些设计原则?

开闭原则

软件就像类一样,模块和功能应该对扩展保持开放,但是对(内部)修改做出关闭.

如何理解开闭原则?当有变化来临时,应该尽量不要更改现有的代码(关闭),而是结合业务场景,应用设计模式扩展现有现有功能.

开闭原则也同样适用于模块,库等的修改.

装饰者和适配器是两个很好的例子.

装饰者模式在往现有设计假如新功能的时候,并不是修改现有的类(关闭),而是建立新的装饰类,将现有的类进行封装,这些装饰类提供新的功能(开放),并往外提供相同的接口.

适配器则也是不修改现有代码(关闭),创建符合新接口的类(通过抽象类或接口),并通过封装现有类(开放),达到接口转换的目的.

依赖倒置原则

这个原则的目的是使得:

  • 上层模块不应该依赖于下层模块(当然下层也不能依赖于上层),他们都应该依赖一个中间的抽象层.

  • 抽象不能依赖于具体实现.相反,实现应该基于抽象.

解释一下,上层模块和下层之间仅依赖抽象(抽象类或者接口),试想一下,假如上层模块依赖于下层的具体类,那上层需要new出每个具体的类,假如一个商店有20种笔,每种笔是一个类,那么这个商店要依赖20个这样的类,耦合度太高.假如我们为这20个品牌的笔提供一个抽象的接口,那么我们要的只是一个抽象类的集合.这样上层和下层会彻底解耦.

另外,我们所有的具体类必须派生自一个抽象类,而不是具体类.这样的原因是不利于重用,想象一下我们有一天想要将下层组件A全部替换到另一个下层组件B,我们这个具体类的实现会显得很丑陋:对A合理的父类实现对B可能就不合理,所以我们应该应该依赖于抽象而不是具体类.

下面这个清单可以用来被检查这个原则:

  • 上层类种属性不能持有具体类的引用.
  • 下层类不能派生自一个具体类.
  • 不要覆盖基类中已经覆盖的方法(所以,基类种最好不要有实现).

抽象工厂是反转依赖的例子.采用抽象工厂,我们可以将上层对下层具体类的依赖转变成,对抽象工厂和抽象类(由具体类实现)的依赖,从而达到了上下层的解耦.

单一职责原则

单一职责原则规定了每个类都有应该有一个单一的功能,并且该功能由这个类完全封装起来.这样做的好处就是,一个类或者模块应该有且只有一个引起改变的原因.

这个原则很好理解,比如,在web中,内容(html)和样式(css)应该分开.但是,却很难做到,以至于有的设计模式不得不牺牲这点,比如组合迭代器模式.

最少知识原则

最少知识原则规定了一个对象应该和哪些对象进行交互,意图是减少对象之间的依赖关系.这个原则可以被总结为:只和你的密友谈话.

最少知识原则规定,对任何对象而言,在该对象的方法内,我们只应该调用属于一下范围的方法:

  • 该对象本身
  • 被当做方法参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 对象的任何组件

这个原则只是指导性的,试想一下假如我们完全按照这个原则,那我们会产生多少个wrapper来封装对象方法的二级调用(调用对象方法所返回的对象 的方法).

好莱坞原则

don’t call us, we’ll call you

这句在好莱坞电影中经常出现的台词也是一种设计原则,是不是感觉酷酷的?

在软件过程中,经常有这样的场景,我们需要”在xxx发生后,调用xxx来告诉我”,意思是,我不愿意一遍遍地询问xxx发生了么,而是让你主动告诉我们.

想一想,回调,事件驱动就是这个原则很好的例子.

接口隔离原则

这个原则的意思是:客户端不应该依赖于他们不使用的接口.

结合场景,接口提供的方法应该只和接口要表达的行为相关,与接口不相关的方法不应该在此接口中提供.比如,一个叫Gun的接口,不应该有zoom()方法,因为不一定所有的枪都有瞄准镜.

接口隔离带来的好处是,我们的接口功能划分明确,一个大的接口会被拆分为更小的接口,从而使软件的复用性大大增加.

里氏替换原则(待补)

里氏替换原则指出了在面向对象的设计中,什么时候可以使用继承,什么时候不应该适用继承,以及其中蕴含的原理.里氏替换原则可以被归纳为一句话:子类必须能够替换成它们的基类。

什么时候适用继承?

在一个软件系统中,子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。 当你代码中有了 instanceof 或者其他类似根据子类类别不同采取不同的动作时,就应该考虑是否违反了里氏替换原则:表明此处子类不能替换基类,必须要做区分才能正确运行.

参考资料:

依赖倒置:

设计原则:

最小知识原则:

好莱坞原则:

里氏替换原则: