SOLID原则

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-05-21

SOLID原则:开发者进行OOP(面向对象编程语言)开发时需要遵守的5个准则;

  • 单一职责原则(SRP):表明软件组件(函数、类、模块)必须专注于单一的任务。
  • 开/闭原则(OCP):表明软件设计时必须时刻考虑到代码的扩展性,使得程序之后的发展必须最少地修改已有的代码;
  • 里式替换原则(LSP):表明只要继承的是同一个接口,程序里任意一个类都可以被其他的类替换,在替换完成后,不需要其他额外的工作程序就能照常运行;
  • 接口隔离原则(ISP):表明我们应该将那些非常大的接口,拆分为一些小的更具体的接口。
  • 依赖反转原则(DIP):表明一个方法应该遵从依赖于抽象(接口)而不是一个实例(类)的概念;

SRP 单一职责原则

举例:Person不应该去实现Email的验证功能,应该有 Email类自行实现。

class Email {
  public email: string;
  constructor(email: string) {
    if (this.validateEmail(email)) {
      this.email = email;
    } else {
      throw new Error("Invalid email!");
    }
  }

  private validateEmail(email: string) {
    var re = /\S+@\S+\.\S+/;
    return re.test(email);
  }

  get() :string {
    return this.email;
  }
}

class Person {
  public name: string;
  public email: Email; // 确保遵循SRP原则,只需要知道是Email类型,而无需去管Email的验证问题;
  constructor (name: string, email: Email) {
    this.name = name;
    this.email = email;
  }
}

var p = new Person('jack', new Email('a@abc.com'));

LSP 里氏替换原则

LSP 表示派生类对象能够替换基类对象被使用。

举例:当无论我们使用 cookie 存储 还是使用 localStorage 存储,都无须修改 LikesController 的代码,可以互相替换;

这种行为成为可能 是因为 它们也遵循了 DIP 原则,DIP原则表示一个方法应该遵从依赖于抽象而不是一个实例,在这里的体现就是,LikesController 依赖于 SaveDataInterface(抽象),而不是 CookieSaveLocalStorageSave(实例)。

interface SaveDataInterface {
  save(entity: any): number;
}

class CookieSave implements SaveDataInterface {
  save(entity: any): number {
    var id = Math.floor(Math.random() * 100);
    // 存储逻辑 ...
    return id;
  }
}

class LikesController {
  private savaData: SaveDataInterface;

  constructor(savaData: SaveDataInterface) {
    this.saveData = saveData;
  }

  public savaAsLikes(articleId: number) {
    return this.saveData.save(articleId);
  }
}

// 当使用cookie存储时
var likesController = new LikesController(new CookieSave());

// 当使用localStorage存储时
class LocalStorageSave implements SaveDataInterface {
  save(entity: any): number {
    // 存储逻辑
  }
}
var likesController2 = new LikesController(new LocalStorageSave());

ISP 接口隔离原则

接口隔离原则代表着任何客户端不应强制依赖于它没有使用到的方法,为了遵循 ISP,我们需要记住,在应用组件内声明 API 时,声明多个针对特定客户端的接口,要好于声明一个大而全的接口。

interface Car {
  getSpeed(): number;
  isLightsOn(): boolean;
  isLightsOff(): boolean;
  startRadio(): void;
  stopRadio(): void;
}

// 如果有一个类基于 Car 的依赖(客户端),但只想使用它的 radio相关方法,那么就会违背 ISP原则;
// 我们应该将其分离成多个针对客户端的接口

interface Car {
  getSpeed(): number;
}

interface CarRadio {
  startRadio(): void;
  stopRadio(): void;
}

interface CarLights {
  isLightsOn(): boolean;
  isLightsOff(): boolean;
}