SOLID原则已经忘了吧?

332 阅读3分钟

SOLID 原则是面向对象编程和设计的五个基本原则,它们帮助开发人员编写高质量、易于维护和可扩展的软件系统。下面是对每个原则的简要说明:

  1. 单一职责原则(SRP):一个类应该只有一个引起变化的原因,即一个类只应该有一个职责。这样可以确保类的变化不会影响到其他的功能,提高了类的内聚性和代码的可维护性。
  2. 开闭原则(OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着在不修改现有代码的情况下,通过扩展来实现新功能或变化。
  3. 里式替换原则(LSP):子类必须能够替换其父类并出现在父类可以出现的任何地方,而不破坏程序的正确性。这确保了代码的兼容性和一致性。
  4. 接口隔离原则(ISP):客户端不应该依赖于它不需要的接口。接口应该被细化,以便于客户端根据需要选择性地实现接口,避免了不必要的依赖关系。
  5. 依赖反转原则(DIP):高层模块不应该依赖于低层模块,它们都应该依赖于抽象。这可以通过依赖注入等方式实现,以提高代码的灵活性、可测试性和可维护性。

我们将使用一个简单的场景来演示这些原则,即一个简单的图形绘制应用。

假设我们的图形绘制应用有以下需求:

  1. 绘制不同类型的图形(如圆形、矩形)。
  2. 可以将图形保存到文件中。

现在,我们将使用 SOLID 原则来设计和实现这个应用。

单一职责原则(SRP)

// 单一职责原则示例
class Circle {
  constructor(radius) {
    this.radius = radius;
  }

  draw() {
    // 绘制圆形的代码
  }

  saveToFile() {
    // 将圆形保存到文件的代码
  }
}

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  draw() {
    // 绘制矩形的代码
  }

  saveToFile() {
    // 将矩形保存到文件的代码
  }
}

在这个示例中,Circle 类和 Rectangle 类各自负责绘制和保存图形,遵循了单一职责原则。

开闭原则(OCP)

// 开闭原则示例
class Circle {
  constructor(radius) {
    this.radius = radius;
  }

  draw() {
    // 绘制圆形的代码
  }
}

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  draw() {
    // 绘制矩形的代码
  }
}

// 新增一个三角形类
class Triangle {
  constructor(base, height) {
    this.base = base;
    this.height = height;
  }

  draw() {
    // 绘制三角形的代码
  }
}

通过新增 Triangle 类来扩展应用,而不需要修改现有的 CircleRectangle 类,符合开闭原则。

里式替换原则(LSP)

// 里式替换原则示例
class Shape {
  draw() {
    // 绘制图形的代码
  }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
}

通过创建一个通用的基类 ShapeCircleRectangle 都可以作为其子类进行替换使用。

接口隔离原则(ISP)

// 接口隔离原则示例
class Drawable {
  draw() {
    // 绘制图形的代码
  }
}

class Saveable {
  saveToFile() {
    // 将图形保存到文件的代码
  }
}

class Circle extends Drawable {
  // 实现绘制方法
}

class Rectangle extends Drawable, Saveable {
  // 实现绘制和保存方法
}

通过将功能接口分离成 DrawableSaveable 接口,Circle 只需实现绘制方法,而 Rectangle 则需要同时实现绘制和保存方法。

依赖反转原则(DIP)

// 依赖反转原则示例
class FileSaver {
  saveToFile() {
    // 将图形保存到文件的代码
  }
}

class Circle {
  constructor(fileSaver) {
    this.fileSaver = fileSaver;
  }

  draw() {
    // 绘制圆形的代码
  }

  saveToFile() {
    this.fileSaver.saveToFile();
  }
}

class Rectangle {
  constructor(fileSaver) {
    this.fileSaver = fileSaver;
  }

  draw() {
    // 绘制矩形的代码
  }

  saveToFile() {
    this.fileSaver.saveToFile();
  }
}

通过将保存功能的实现抽象成 FileSaver 类,并通过构造函数注入到 CircleRectangle 中,实现了依赖反转。

遵循这些原则可以帮助开发人员编写出结构良好、易于理解和扩展的代码,提高软件系统的质量和可维护性。