Skip to content

设计原则

这篇文章将介绍在软件设计过程中一些重要的设计原则。这些原则是一些经验法则,可以帮助我们设计出更加灵活、可维护和可扩展的软件。

SOLID 原则

单一职责原则 (SRP)

单一职责原则指出,一个类应该只有一个引起它变化的原因。换句话说,一个类应该仅有一个职责。遵循这一原则可以使类更易于理解、维护和扩展。

JavaScript
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  getUserInfo() {
    return `Name: ${this.name}, Email: ${this.email}`;
  }
}

class UserRepository {
  save(user) {
    // 保存用户到数据库
  }
}

开放封闭原则 (OCP)

开放封闭原则指出,软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着我们应该能够扩展一个类的行为,而不需要修改现有的代码。

JavaScript
class Shape {
  area() {
    throw new Error('This method must be overridden');
  }
}

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

  area() {
    return this.width * this.height;
  }
}

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

  area() {
    return Math.PI * this.radius * this.radius;
  }
}

里氏替换原则 (LSP)

里氏替换原则指出,子类必须能够替换其基类,并且程序的行为不会改变。遵循这一原则可以确保继承体系的正确性和一致性。

JavaScript
class Bird {
  fly() {
    console.log('Flying');
  }
}

class Sparrow extends Bird {
  // Sparrow 可以替换 Bird
}

class Ostrich extends Bird {
  fly() {
    throw new Error("Ostriches can't fly");
  }
}

接口隔离原则 (ISP)

接口隔离原则指出,客户端不应该被迫依赖于它们不使用的方法。换句话说,一个类对另一个类的依赖应该建立在最小的接口上。

JavaScript
class Printer {
  print() {
    throw new Error('This method must be overridden');
  }
}

class Scanner {
  scan() {
    throw new Error('This method must be overridden');
  }
}

class AllInOnePrinter extends Printer {
  print() {
    console.log('Printing');
  }
  scan() {
    console.log('Scanning');
  }
}

依赖倒置原则 (DIP)

依赖倒置原则指出,高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。遵循这一原则可以减少类之间的耦合,提高系统的灵活性和可维护性。

JavaScript
class Database {
  connect() {
    throw new Error('This method must be overridden');
  }
}

class MySQLDatabase extends Database {
  connect() {
    console.log('Connecting to MySQL');
  }
}

class UserService {
  constructor(database) {
    this.database = database;
  }

  connectToDatabase() {
    this.database.connect();
  }
}

const mySQLDatabase = new MySQLDatabase();
const userService = new UserService(mySQLDatabase);
userService.connectToDatabase(); // Connecting to MySQL

迪米特法则 (LoD)

迪米特法则指出,一个对象应该对其他对象有最少的了解。换句话说,一个对象不应该知道它操作的对象的内部细节。遵循这一原则可以减少类之间的耦合,提高系统的模块化程度。

JavaScript
class Engine {
  start() {
    console.log('Engine started');
  }
}

class Car {
  constructor() {
    this.engine = new Engine();
  }

  start() {
    this.engine.start();
  }
}

const car = new Car();
car.start(); // Engine started

合成复用原则 (CRP)

合成复用原则指出,应该尽量使用对象组合,而不是继承来达到复用的目的。组合可以使系统更加灵活,降低类之间的耦合度。

JavaScript
class Engine {
  start() {
    console.log('Engine started');
  }
}

class Car {
  constructor(engine) {
    this.engine = engine;
  }

  start() {
    this.engine.start();
  }
}

const engine = new Engine();
const car = new Car(engine);
car.start(); // Engine started

最少知识原则 (LKP)

最少知识原则指出,一个对象应该对其他对象有最少的了解。换句话说,一个对象不应该知道它操作的对象的内部细节。

JavaScript
class Engine {
  start() {
    console.log('Engine started');
  }
}

class Car {
  constructor() {
    this.engine = new Engine();
  }

  start() {
    this.engine.start();
  }
}

const car = new Car();
car.start(); // Engine started

最小意外原则 (MMP)

最小意外原则指出,一个类应该只做它被设计为做的事情,不应该有意外的行为。遵循这一原则可以使类更易于理解、维护和扩展。

JavaScript
class Calculator {
  add(a, b) {
    return a + b;
  }
}

const calculator = new Calculator();
console.log(calculator.add(1, 2)); // 3

重用原则

重用原则指出,应该尽量重用现有的代码,而不是重复编写相同的代码。重用可以减少代码的复杂性,提高代码的可维护性。

JavaScript
class MathOperations {
  add(a, b) {
    return a + b;
  }

  subtract(a, b) {
    return a - b;
  }
}

const mathOps = new MathOperations();
console.log(mathOps.add(5, 3)); // 8
console.log(mathOps.subtract(5, 3)); // 2

简单原则

简单原则指出,一个类应该只有一个引起它变化的原因。换句话说,一个类应该仅有一个职责。遵循这一原则可以使类更易于理解、维护和扩展。

JavaScript
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  getUserInfo() {
    return `Name: ${this.name}, Email: ${this.email}`;
  }
}