前端常见的20种设计模式及其应用

178 阅读3分钟

1. 单例模式 (Singleton)

  • 目的: 确保一个类只有一个实例,并提供一个全局访问点。
  • 应用场景: 全局状态管理、配置管理、缓存管理等。
// singleton.js
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    this.data = {};
    Singleton.instance = this;
  }

  setData(key, value) {
    this.data[key] = value;
  }

  getData(key) {
    return this.data[key];
  }
}

const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2); // true
instance1.setData('name', 'Alice');
console.log(instance2.getData('name')); // Alice

2. 工厂模式 (Factory)

  • 目的: 将对象的创建逻辑封装起来,客户端无需关心具体创建过程。
  • 应用场景: 创建不同类型的UI组件、API请求等。
// factory.js
class Button {
  constructor(text) {
    this.text = text;
  }
  render() {
    return `<button>${this.text}</button>`;
  }
}

class Input {
  constructor(placeholder) {
    this.placeholder = placeholder;
  }
  render() {
    return `<input placeholder="${this.placeholder}" />`;
  }
}

class UIComponentFactory {
  create(type, options) {
    switch (type) {
      case 'button':
        return new Button(options.text);
      case 'input':
        return new Input(options.placeholder);
      default:
        throw new Error('Invalid component type');
    }
  }
}

const factory = new UIComponentFactory();
const button = factory.create('button', { text: 'Click Me' });
const input = factory.create('input', { placeholder: 'Enter text' });

console.log(button.render());
console.log(input.render());

3. 抽象工厂模式 (Abstract Factory)

  • 目的: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。
  • 应用场景: 创建不同主题的UI组件、不同平台的API客户端等。
// abstract_factory.js
class LightButton {
  render() {
    return `<button style="background-color: #eee;">Light Button</button>`;
  }
}

class DarkButton {
  render() {
    return `<button style="background-color: #333; color: white;">Dark Button</button>`;
  }
}

class LightInput {
  render() {
    return `<input style="border: 1px solid #eee;" placeholder="Light Input" />`;
  }
}

class DarkInput {
  render() {
    return `<input style="border: 1px solid #333; color: white; background-color: #555;" placeholder="Dark Input" />`;
  }
}

class LightThemeFactory {
  createButton() {
    return new LightButton();
  }
  createInput() {
    return new LightInput();
  }
}

class DarkThemeFactory {
  createButton() {
    return new DarkButton();
  }
  createInput() {
    return new DarkInput();
  }
}

function renderUI(factory) {
  const button = factory.createButton();
  const input = factory.createInput();
  console.log(button.render());
  console.log(input.render());
}

const lightTheme = new LightThemeFactory();
const darkTheme = new DarkThemeFactory();

renderUI(lightTheme);
renderUI(darkTheme);

4. 建造者模式 (Builder)

  • 目的: 将一个复杂对象的构建与其表示分离,使得相同的构建过程可以创建不同的表示。
  • 应用场景: 构建复杂的配置对象、API请求参数等。
// builder.js
class Request {
  constructor() {
    this.method = 'GET';
    this.url = '';
    this.headers = {};
    this.body = null;
  }
}

class RequestBuilder {
  constructor() {
    this.request = new Request();
  }

  setMethod(method) {
    this.request.method = method;
    return this;
  }

  setUrl(url) {
    this.request.url = url;
    return this;
  }

  setHeader(key, value) {
    this.request.headers[key] = value;
    return this;
  }

  setBody(body) {
    this.request.body = body;
    return this;
  }

  build() {
    return this.request;
  }
}

const request = new RequestBuilder()
  .setMethod('POST')
  .setUrl('/api/users')
  .setHeader('Content-Type', 'application/json')
  .setBody({ name: 'John Doe' })
  .build();

console.log(request);

5. 原型模式 (Prototype)

  • 目的: 通过复制现有对象来创建新对象,避免重复的初始化过程。
  • 应用场景: 创建大量相似对象、克隆复杂对象等。
// prototype.js
class User {
  constructor(name, age, address) {
    this.name = name;
    this.age = age;
    this.address = address;
  }

  clone() {
    return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
  }
}

const user1 = new User('Alice', 30, { city: 'New York' });
const user2 = user1.clone();
user2.name = 'Bob';
user2.address.city = 'London';

console.log(user1);
console.log(user2);

6. 适配器模式 (Adapter)

  • 目的: 将一个类的接口转换成客户端所期望的另一个接口,使得原本不兼容的类可以一起工作。
  • 应用场景: 集成第三方库、处理不同格式的数据等。
// adapter.js
class LegacyAPI {
  constructor() {
    this.data = {
      firstName: 'John',
      lastName: 'Doe',
    };
  }

  getLegacyData() {
    return this.data;
  }
}

class NewAPI {
  constructor() {
    this.data = {
      name: 'Jane Smith',
      age: 25,
    };
  }

  getNewData() {
    return this.data;
  }
}

class APIAdapter {
  constructor(api) {
    this.api = api;
  }
  getData() {
    if (this.api instanceof LegacyAPI) {
      const legacyData = this.api.getLegacyData();
      return {
        name: `${legacyData.firstName} ${legacyData.lastName}`,
      };
    } else if (this.api instanceof NewAPI) {
      return this.api.getNewData();
    }
    return null;
  }
}

const legacyAPI = new LegacyAPI();
const newAPI = new NewAPI();

const legacyAdapter = new APIAdapter(legacyAPI);
const newAdapter = new APIAdapter(newAPI);

console.log(legacyAdapter.getData());
console.log(newAdapter.getData());

7. 桥接模式 (Bridge)

  • 目的: 将抽象部分与其实现部分分离,使它们可以独立地变化。
  • 应用场景: 处理不同操作系统、不同数据库的兼容性问题等。
// bridge.js
class Renderer {
  renderCircle(x, y, radius, color) {}
  renderSquare(x, y, size, color) {}
}

class CanvasRenderer extends Renderer {
  renderCircle(x, y, radius, color) {
    console.log(`Canvas: Circle at (${x}, ${y}) with radius ${radius} and color ${color}`);
  }
  renderSquare(x, y, size, color) {
    console.log(`Canvas: Square at (${x}, ${y}) with size ${size} and color ${color}`);
  }
}

class SVGRenderer extends Renderer {
  renderCircle(x, y, radius, color) {
    console.log(`SVG: Circle at (${x}, ${y}) with radius ${radius} and color ${color}`);
  }
  renderSquare(x, y, size, color) {
    console.log(`SVG: Square at (${x}, ${y}) with size ${size} and color ${color}`);
  }
}

class Shape {
  constructor(renderer) {
    this.renderer = renderer;
  }
  draw() {}
}

class Circle extends Shape {
  constructor(x, y, radius, color, renderer) {
    super(renderer);
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
  }
  draw() {
    this.renderer.renderCircle(this.x, this.y, this.radius, this.color);
  }
}

class Square extends Shape {
  constructor(x, y, size, color, renderer) {
    super(renderer);
    this.x = x;
    this.y = y;
    this.size = size;
    this.color = color;
  }
  draw() {
    this.renderer.renderSquare(this.x, this.y, this.size, this.color);
  }
}

const canvasRenderer = new CanvasRenderer();
const svgRenderer = new SVGRenderer();

const circle1 = new Circle(10, 10, 5, 'red', canvasRenderer);
const square1 = new Square(20, 20, 10, 'blue', svgRenderer);

circle1.draw();
square1.draw();

8. 组合模式 (Composite)

  • 目的: 将对象组合成树形结构,以表示“部分-整体”的层次结构,使得客户端可以统一对待单个对象和组合对象。
  • 应用场景: 构建UI组件树、文件系统等。
// composite.js
class Graphic {
  render() {}
}

class CircleGraphic extends Graphic {
  constructor(x, y, radius) {
    super();
    this.x = x;
    this.y = y;
    this.radius = radius;
  }
  render() {
    console.log(`Circle at (${this.x}, ${this.y}) with radius ${this.radius}`);
  }
}

class SquareGraphic extends Graphic {
  constructor(x, y, size) {
    super();
    this.x = x;
    this.y = y;
    this.size = size;
  }
  render() {
    console.log(`Square at (${this.x}, ${this.y}) with size ${this.size}`);
  }
}

class CompositeGraphic extends Graphic {
  constructor() {
    super();
    this.children = [];
  }
  add(graphic) {
    this.children.push(graphic);
  }
  render() {
    this.children.forEach((child) => child.render());
  }
}

const circle1 = new CircleGraphic(10, 10, 5);
const square1 = new SquareGraphic(20, 20, 10);
const composite1 = new CompositeGraphic();
composite1.add(circle1);
composite1.add(square1);

const circle2 = new CircleGraphic(50, 50, 8);
const composite2 = new CompositeGraphic();
composite2.add(composite1);
composite2.add(circle2);

composite2.render();

9. 装饰器模式 (Decorator)

  • 目的: 动态地给对象添加额外的职责,而无需修改其原始类。
  • 应用场景: 添加日志、缓存、权限控制等功能。
// decorator.js
class Coffee {
  cost() {
    return 5;
  }
  description() {
    return 'Coffee';
  }
}

class MilkDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
  cost() {
    return this.coffee.cost() + 2;
  }
  description() {
    return `${this.coffee.description()}, Milk`;
  }
}

class SugarDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
  cost() {
    return this.coffee.cost() + 1;
  }
  description() {
    return `${this.coffee.description()}, Sugar`;
  }
}

let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);

console.log(`${coffee.description()} costs $${coffee.cost()}`);

10. 外观模式 (Facade)

  • 目的: 为复杂的子系统提供一个简单的接口,隐藏子系统的复杂性。
  • 应用场景: 简化API调用、封装复杂逻辑等。
// facade.js
class SubsystemA {
  operationA() {
    console.log('Subsystem A operation');
  }
}

class SubsystemB {
  operationB() {
    console.log('Subsystem B operation');
  }
}

class Facade {
  constructor() {
    this.subsystemA = new SubsystemA();
    this.subsystemB = new SubsystemB();
  }

  operation() {
    this.subsystemA.operationA();
    this.subsystemB.operationB();
  }
}

const facade = new Facade();
facade.operation();

11. 享元模式 (Flyweight)

  • 目的: 通过共享对象来减少内存使用,尤其是在需要创建大量相似对象时。
  • 应用场景: 文本编辑器、游戏中的角色等。
// flyweight.js
class Character {
  constructor(font, color) {
    this.font = font;
    this.color = color;
  }
  render(x, y, char) {
    console.log(`Render ${char} at (${x}, ${y}) with font ${this.font} and color ${this.color}`);
  }
}

class CharacterFactory {
  constructor() {
    this.cache = {};
  }
  getCharacter(font, color) {
    const key = `${font}-${color}`;
    if (!this.cache[key]) {
      this.cache[key] = new Character(font, color);
    }
    return this.cache[key];
  }
}

const factory = new CharacterFactory();
const charA = factory.getCharacter('Arial', 'black');
const charB = factory.getCharacter('Arial', 'black');
const charC = factory.getCharacter('Times New Roman', 'red');

charA.render(10, 10, 'A');
charB.render(20, 20, 'B');
charC.render(30, 30, 'C');

console.log(charA === charB); // true

12. 代理模式 (Proxy)

  • 目的: 为另一个对象提供一个占位符或代理,以控制对该对象的访问。
  • 应用场景: 延迟加载、权限控制、缓存等。
// proxy.js
class RealImage {
  constructor(filename) {
    this.filename = filename;
    this.loadFromDisk();
  }
  loadFromDisk() {
    console.log(`Loading image from ${this.filename}`);
  }
  display() {
    console.log(`Displaying image ${this.filename}`);
  }
}

class ProxyImage {
  constructor(filename) {
    this.filename = filename;
    this.realImage = null;
  }
  display() {
    if (!this.realImage) {
      this.realImage = new RealImage(this.filename);
    }
    this.realImage.display();
  }
}

const image1 = new ProxyImage('image1.jpg');
image1.display();
image1.display();

13. 责任链模式 (Chain of Responsibility)

  • 目的: 将请求的发送者和接收者解耦,允许多个对象处理请求,直到其中一个处理它。
  • 应用场景: 事件处理、表单验证、日志记录等。
// chain_of_responsibility.js
class Handler {
  constructor(successor = null) {
    this.successor = successor;
  }
  handle(request) {
    if (this.successor) {
      this.successor.handle(request);
    }
  }
}

class ConcreteHandlerA extends Handler {
  handle(request) {
    if (request === 'A') {
      console.log('Handler A handles the request');
    } else {
      super.handle(request);
    }
  }
}

class ConcreteHandlerB extends Handler {
  handle(request) {
    if (request === 'B') {
      console.log('Handler B handles the request');
    } else {
      super.handle(request);
    }
  }
}

const handlerA = new ConcreteHandlerA();
const handlerB = new ConcreteHandlerB();
handlerA.successor = handlerB;

handlerA.handle('A');
handlerA.handle('B');
handlerA.handle('C');

14. 命令模式 (Command)

  • 目的: 将请求封装成对象,从而允许参数化客户端请求、排队请求、记录请求日志等。
  • 应用场景: 撤销/重做功能、事务处理等。
// command.js
class Receiver {
  action(command) {
    console.log(`Receiver: Executing command ${command}`);
  }
}

class Command {
  constructor(receiver, command) {
    this.receiver = receiver;
    this.command = command;
  }
  execute() {
    this.receiver.action(this.command);
  }
}

class Invoker {
  constructor() {
    this.commands = [];
  }
  addCommand(command) {
    this.commands.push(command);
  }
  executeCommands() {
    this.commands.forEach((command) => command.execute());
    this.commands = [];
  }
}

const receiver = new Receiver();
const command1 = new Command(receiver, 'Command 1');
const command2 = new Command(receiver, 'Command 2');

const invoker = new Invoker();
invoker.addCommand(command1);
invoker.addCommand(command2);
invoker.executeCommands();

15. 迭代器模式 (Iterator)

  • 目的: 提供一种方法顺序访问一个聚合对象中的元素,而无需暴露其底层表示。
  • 应用场景: 遍历数组、集合等。
// iterator.js
class Iterator {
  constructor(items) {
    this.items = items;
    this.index = 0;
  }
  hasNext() {
    return this.index < this.items.length;
  }
  next() {
    return this.hasNext() ? this.items[this.index++] : null;
  }
}

class Aggregate {
  constructor(items) {
    this.items = items;
  }
  createIterator() {
    return new Iterator(this.items);
  }
}

const aggregate = new Aggregate([1, 2, 3, 4, 5]);
const iterator = aggregate.createIterator();

while (iterator.hasNext()) {
  console.log(iterator.next());
}

16. 中介者模式 (Mediator)

  • 目的: 定义一个对象来封装一组对象如何交互,从而减少对象之间的直接依赖。
  • 应用场景: UI组件之间的交互、聊天室等。
// mediator.js
class Colleague {
  constructor(mediator) {
    this.mediator = mediator;
  }
  send(message) {
    this.mediator.send(message, this);
  }
  receive(message) {}
}

class ConcreteColleagueA extends Colleague {
  receive(message) {
    console.log(`Colleague A received: ${message}`);
  }
}

class ConcreteColleagueB extends Colleague {
  receive(message) {
    console.log(`Colleague B received: ${message}`);
  }
}

class Mediator {
  constructor() {
    this.colleagues = [];
  }
  addColleague(colleague) {
    this.colleagues.push(colleague);
  }
  send(message, sender) {
    this.colleagues.forEach((colleague) => {
      if (colleague !== sender) {
        colleague.receive(message);
      }
    });
  }
}

const mediator = new Mediator();
const colleagueA = new ConcreteColleagueA(mediator);
const colleagueB = new ConcreteColleagueB(mediator);

mediator.addColleague(colleagueA);
mediator.addColleague(colleagueB);

colleagueA.send('Hello from A');
colleagueB.send('Hello from B');

17. 备忘录模式 (Memento)

  • 目的: 在不破坏封装性的前提下,捕获对象的内部状态,以便在需要时恢复到之前的状态。
  • 应用场景: 撤销/重做功能、游戏存档等。
// memento.js
class Originator {
  constructor(state) {
    this.state = state;
  }
  setState(state) {
    this.state = state;
  }
  getState() {
    return this.state;
  }
  saveStateToMemento() {
    return new Memento(this.state);
  }
  getStateFromMemento(memento) {
    this.state = memento.getState();
  }
}

class Memento {
  constructor(state) {
    this.state = state;
  }
  getState() {
    return this.state;
  }
}

class Caretaker {
  constructor() {
    this.mementos = [];
  }
  addMemento(memento) {
    this.mementos.push(memento);
  }
  getMemento(index) {
    return this.mementos[index];
  }
}

const originator = new Originator('State 1');
const caretaker = new Caretaker();

caretaker.addMemento(originator.saveStateToMemento());
originator.setState('State 2');
caretaker.addMemento(originator.saveStateToMemento());
originator.setState('State 3');

console.log(`Current state: ${originator.getState()}`);

originator.getStateFromMemento(caretaker.getMemento(1));
console.log(`Restored state: ${originator.getState()}`);

18. 观察者模式 (Observer)

  • 目的: 定义对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会收到通知。
  • 应用场景: 事件监听、数据绑定等。
// observer.js
class Subject {
  constructor() {
    this.observers = [];
  }
  addObserver(observer) {
    this.observers.push(observer);
  }
  removeObserver(observer) {
    this.observers = this.observers.filter((obs) => obs !== observer);
  }
  notify(data) {
    this.observers.forEach((observer) => observer.update(data));
  }
}

class Observer {
  update(data) {}
}

class ConcreteObserverA extends Observer {
  update(data) {
    console.log(`Observer A received: ${data}`);
  }
}

class ConcreteObserverB extends Observer {
  update(data) {
    console.log(`Observer B received: ${data}`);
  }
}

const subject = new Subject();
const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();

subject.addObserver(observerA);
subject.addObserver(observerB);

subject.notify('New data available');
subject.removeObserver(observerA);
subject.notify('Another update');

19. 状态模式 (State)

  • 目的: 允许对象在内部状态改变时改变其行为,使其看起来好像修改了它的类。
  • 应用场景: 订单状态管理、游戏角色状态等。
// state.js
class State {
  handle() {}
}

class ConcreteStateA extends State {
  handle(context) {
    console.log('State A: Handling request');
    context.setState(new ConcreteStateB());
  }
}

class ConcreteStateB extends State {
  handle(context) {
    console.log('State B: Handling request');
    context.setState(new ConcreteStateA());
  }
}

class Context {
  constructor() {
    this.state = new ConcreteStateA();
  }
  setState(state) {
    this.state = state;
  }
  request() {
    this.state.handle(this);
  }
}

const context = new Context();
context.request();
context.request();
context.request();

20. 策略模式 (Strategy)

  • 目的: 定义一系列算法,将每个算法封装起来,并使它们可以互相替换,使得算法可以独立于使用它的客户端而变化。
  • 应用场景: 排序算法、支付方式、数据验证等。
// strategy.js
class Strategy {
  execute() {}
}

class ConcreteStrategyA extends Strategy {
  execute(data) {
    console.log(`Strategy A: Processing ${data}`);
  }
}

class ConcreteStrategyB extends Strategy {
  execute(data) {
    console.log(`Strategy B: Processing ${data}`);
  }
}

class Context {
  constructor(strategy) {
    this.strategy = strategy;
  }
  setStrategy(strategy) {
    this.strategy = strategy;
  }
  executeStrategy(data) {
    this.strategy.execute(data);
  }
}

const strategyA = new ConcreteStrategyA();
const strategyB = new ConcreteStrategyB();

const context = new Context(strategyA);
context.executeStrategy('data1');

context.setStrategy(strategyB);
context.executeStrategy('data2');