跳至主要內容

SOLID原则

Weiser大约 5 分钟

SOLID原则

SOLID原则

这五条原则是在罗伯特·马丁的著 作《敏捷软件开发:原则、模式与实践》中首次提出的。

SOLID 是让软件设计更易于理解、更加灵活和更易于维护的 五个原则的简称。与生活中所有事情一样,盲目遵守这些原则可能会弊大于利。在程序架构中应用这些原则可能会使其变得过于复杂。我对于是否真的有能够同时应用所有这五条原则的成功软件产品表示怀疑。有原则是件好事,但是也要时刻从实用的角度来 考量,不要把这里的每句话当作放之四海皆准的教条。

单一职责原则

单一职责原则(Single Responsibility Principle):修改一个类的原因只能有一个。

这个原则不仅仅适用于类,对于接口和方法也适用,即一个接口/方法,只负责一件事,这样的话,接口就会变得简单,方法中的代码也会更少,易读,便于维护。

事实上,由于一些其他的因素影响,类的单一职责在项目中是很难保证的。通常,接口和方法的单一职责更容易实现。

开闭原则

开闭原则(Open/closed Principle):对于扩展,类应该是“开放”的;对于修改,类则应是“封闭”的。

如果你可以对一个类进行扩展,可以创建它的子类并对其做任何事情(如新增方法或成员变量、重写基类行为等),那么它就是开放的。有些编程语言允许你通过特殊关键字(例如 final )来限制对于类的进一步扩展, 这样类就不再是“开放”的了。如果某个类已做好了充分的准备并可供其他类使用的话(即其接口已明确定义且以后不会修改),那么该类就是封闭(你可以称之为完整)的。

也就是说,如果一个类已经完成开发、测试和审核工作,而且属于某个框架或者可被其他类的代码直接使用的话,对其代码进行修改就是有风险的。你可以创建一个子类并重写原始类的部分内容以完成不同的行为,而不是直接对原始类的代码进行修改。这样你既可以达成自己的目标,但同时又无需修改已有的原始类客户端。

这条原则并不能应用于所有对类进行的修改中。如果你发现类中存在缺陷,直接对其进行修复即可,不要为它创建子类。子类不应该对其父类的问题负责。

里氏替换原则

(六大设计原则之里氏替换原则(LSP) - 简书 (jianshu.com)open in new window)

里氏替换原则(Liskov Substitution Principle):当拓展一个类时,应该要能在不修改客户端代码的情况下将子类的对象作为父类对象进行传递。

1. 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法

我们可以给父类的非抽象(已实现)方法加final修饰,这样就在语法层面控制了父类非抽象方法被子类重写而违反里氏替换原则。

有时候父类有多个子类(Son1、Son2),但在这些子类中有一个特例(Son2)。要想满足里氏替换原则,又想满足这个子类的功能时,有的伙伴可能会修改父类(Father)的方法。但是,修改了父类的方法又会对其他的子类造成影响,产生更多的错误。这是怎么办呢?我们可以为这个特例(Son2)创建一个新的父类(Father2),这个新的父类拥有原父类的部分功能(Father2并不继承Father,而是持有Father的一个引用,组合Father,调用Father里的功能),又有不同的功能。这样既满足了里氏替换原则,又满足了这个特例的需求。

2. 子类中可以增加自己特有的方法

这个很容易理解,子类继承了父类,拥有了父类和方法,同时还可以定义自己有,而父类没有的方法。这是在继承父类方法的基础上进行功能的扩展,符合里氏替换原则。

3. 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松

4. 当子类的方法实现父类的(抽象)方法时,方法的后置条件(即方法的返回值)要比父类更严格

接口隔离原则

接口隔离原则(Interface Segregation Principle):客户端不应被强迫依赖于其不需要的方法。要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。

接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:

  • 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。
  • 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。

依赖倒置原则

依赖倒置原则(Dependency Inversion Principle):高层次的类不应该依赖于低层次的类,两者都应该依赖于抽象接口。抽象接口不应依赖于具体实现,具体实现应该依赖于抽象接口。