面向对象中的 SOLID 原则

在面向对象程序设计中,经常见到各种设计原则、设计模式。面向对象的优势就是其针对各种场景的成体系的设计模式,当然过于复杂的设计模式也是Java经常被人诟病的一点。而 SOLID 的就是其中最重要的5条设计原则的首字母缩写,不仅仅是Java,任何面向对象设计的语言编程都应该尽量遵循这5条原则,它们分别是:

  1. SRP, Single Responsibility Principle,单一职责原则
  2. OCP, Open Closed Principle,开放封闭原则
  3. LSP, Liskov Substitution Principle,里氏替换原则
  4. ISP, Interface Segregation Principle,接口分离原则
  5. DIP, Dependency Inversion Principle,依赖倒置原则

这些原则是 Robert C. Martin 整理来的,它们使得一个程序员开发的软件更加容易维护和扩展。虽然它们不是进行软件开发的强制性约束,但是如果对这些原则有很好的理解,并且能在自己的代码中考虑这些规则,很可能可以写出更好的面向对象代码。

单一职责原则(SRP)

单一职责是指一个类或者模块应该有且只有一个去改变它的理由,这意味着一个类应该只有一项职责,并且该功能应该由这个类完全封装起来。

如果设计的一个类负责了两项或者以上的工作,那么就应该考虑拆分这个类。一个例子是,想象有一个用于编辑和打印的模块,报表的内容可能被编辑(改变),报表打印的格式也可能改变,这样就认为一个类/模块存在两个改变的原因。 SRP 认为这事实上是两个分离的功能,因此它们应该被分离在不同的类或者模块里。

保持一个类专注于单一的功能点使得类更加健壮,只要符合两个类之间的接口调用,对其中一个类的修改就是安全的。

开放封闭原则(OCP)

开放封闭即,对象(类,模块,函数等)应该是对扩展是开放的,但是对修改是封闭的。

这意味这一个实体允许在不改变它的源代码的前提下变更它的行为。实现开闭原则有两种不同的方式,分别是梅耶开闭原则和多态开闭原则。它们都使用继承解决问题,但是它们是不同的。

梅耶开闭原则认为一个类只应该因为错误而修改,新的或者改变的特性应该通过新建不同的类实现,新建的类通过继承的方式来重用原类的代码,子类可以或可以不拥有原类的接口。这一方式使用对具体类的继承,而多态开闭原则提倡对抽象基类的继承,继承只重用接口规约,而补充用原类的具体实现。已存在的接口对修改是封闭的,并且新的实现必须至少实现那个接口。

里氏替换原则(LSP)

里氏替换原则是对子类型的特别定义。该原则被描述为: 派生类对象能够替换其基类对象被使用。如果对Java,或者某种面向对象语言比较熟悉的话,这一功能应该不陌生,因为一般的OO语言的类型系统都符合这一原则。

接口隔离原则(ISP)

接口隔离原则推荐拆分非常庞大臃肿的接口成为更小的更具体的接口,这样客户将会只需要知道它们感兴趣的方法,这种缩小的接口也称为角色接口(role interface)。也可以说客户端不应该被迫依赖它们不使用的方法。

应该可以这么理解:一个具体类继承了一个接口时,类必须实现接口所有的方法规范,如果该类认为接口定义的某个方法对自己没有作用,不需要实现它,那么可以将这个接口拆分,类只实现自己需要的接口。

依赖反转原则(DIP)

依赖反转比较耳熟,因为经常听到依赖注入(DI),控制反转(IoC)的术语。依赖反转原则是指:实体必须依靠抽象而不是具体实现,它表示高层次的模块不应该依赖于低层次的模块,它们都应该依赖于抽象。

依赖反转是一种特定的解耦形式,高层次的和低层次的对象都应该依赖于相同的抽象接口,一般来说高层次实体引用接口,而低层次类实现该接口,而不是高层次类直接引用低层次类,以此实现解耦。

应用依赖反转原则同样被认为是应用了适配器模式,高层的类定义依赖自己的适配器接口(高层类所依赖的抽象接口),被适配对象同样依赖于适配器接口的抽象(被适配对象实现了这个接口)。适配器模式的典型应用JDBC就符合这一场景。

上面的额几条原则在第四个参考页面有一些示例,如果不能理解,可以在那看看代码。

参考: