单一职责原则

  • Single Responsibility Principle:There should never be more than one reason for a class to change.
  • 单一职责原则最难划分的就是职责,单一职责适用于接口、类,同时也适用于方法,一个方法尽可能做一件事情
  • 最佳实践:接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。

里氏替换原则

  • 继承的利:

    • 代码共享
    • 提高代码的重用性
    • 子类可以形似父类,但又异于父类
    • 提高代码的可扩展性
  • 继承的弊:

    • 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
    • 降低代码的灵活性。子类必须拥有父类的属性和方法
    • 增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改
  • 如何增大利而减小弊?答案就是引入里氏替换原则(Liskov Substitution Principle,LSP)

  • 定义一:If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.(如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。

  • 定义二:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.(所有引用基类的地方必须能透明地使用其子类的对象。)

    第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类,但是反过来就不行了

  • 子类必须完全实现父类的方法

  • 子类可以有自己的个性

  • 覆盖或实现父类的方法时输入参数可以被放大

  • 覆写或实现父类的方法时输出结果可以被缩小

  • 最佳实践:在项目中,采用里氏替换原则时,尽量避免子类的“个性”

依赖倒置原则

  • 依赖倒置原则(Dependence Inversion Principle,DIP)

  • High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

  • 三层含义:

    • 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
    • 抽象不应该依赖细节;
    • 细节应该依赖抽象。
  • 依赖倒置原则应用Java中的表现就是:

    • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
    • 接口或抽象类不依赖于实现类;
    • 实现类依赖接口或抽象类。
  • 更加精简的定义就是“面向接口编程”

  • 采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。

  • 最佳实践:

    • 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备
    • 变量的表面类型尽量是接口或者是抽象类
    • 任何类都不应该从具体类派生
    • 尽量不要覆写基类的方法
    • 结合里氏替换原则使用
  • 依赖倒置原则是6个设计原则中最难以实现的原则,它是实现开闭原则的重要途径,依赖倒置原则没有实现,就别想实现对扩展开放,对修改关闭。在项目中,大家只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心。

接口隔离原则

  • Clients should not be forced to depend upon interfaces that they don’t use.(客户端不应该依赖它不需要的接口。)

  • The dependency of one class to another one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上。)

  • 建立单一接口,不要建立臃肿庞大的接口。再通俗一点讲:接口尽量细化,同时接口中的方法尽量少

  • 与单一职责原则并不冲突,单一职责原则注重的是职责,而接口隔离原则要求接口的方法尽量少

  • 什么是高内聚?高内聚就是提高接口、类、模块的处理能力,减少对外的交互。比如你告诉下属“到奥巴马的办公室偷一个×××文件”,然后听到下属用坚定的口吻回答你:“是,保证完成任务!”一个月后,你的下属还真的把×××文件放到你的办公桌上了,这种不讲任何条件、立刻完成任务的行为就是高内聚的表现。具体到接口隔离原则就是,要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本。

迪米特法则

  • 迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP),虽然名字不同,但描述的是同一个规则:一个对象应该对其他对象有最少的了解

  • Only talk to your immediate friends(只与直接的朋友通信。)

  • 迪米特法则要求类“羞涩”一点,尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private、package-private、protected等访问权限。

  • 如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

  • 最佳实践:迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。其要求的结果就是产生了大量的中转或跳转类,导致系统的复杂性提高,同时也为维护带来了难度。读者在采用迪米特法则时需要反复权衡,既做到让结构清晰,又做到高内聚低耦合。

开闭原则

  • Software entities like classes,modules and functions should be open for extension but closed for modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。)

  • 开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段

  • 重要性:

    • 对测试友好
    • 提高复用性
    • 提高可维护性
    • 面向对象开发的要求
  • 最佳实践(SOLID)

    • ● Single Responsibility Principle:单一职责原则
    • ● Open Closed Principle:开闭原则
    • ● Liskov Substitution Principle:里氏替换原则
    • ● Law of Demeter:迪米特法则
    • ● Interface Segregation Principle:接口隔离原则
    • ● Dependence Inversion Principle:依赖倒置原则