代码改变世界

实用指南:JavaScript 行为型设计模式详解

2025-09-14 10:11  tlnshuju  阅读(7)  评论(0)    收藏  举报

1. 观察者模式

1.1. 使用场景

观察者模式用于对象间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都能收到通知并自动更新。常用于事件处理、通知系统。在前端中,观察者模式用于实现事件监听、数据绑定等功能。

1.2. 代码实现

class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers(message) {
this.observers.forEach(observer => observer.update(message));
}
}
class Observer {
update(message) {
console.log('Observer received:', message);
}
}
// 使用观察者模式
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('New update available'); // Observer received: New update available

1.3. 详细解释

  • Subject:发布者,维护一个观察者列表,提供方法来添加、移除和通知观察者。

  • Observer:观察者,提供 update 方法来响应发布者的通知。

  • 观察者模式适合事件系统或数据模型更新的场景。

1.4. 实际应用

观察者模式常用于事件驱动系统,如 DOM 事件监听器、Vue 或 React 的响应式系统。

2. 发布订阅模式

2.1. 使用场景

发布订阅模式用于实现松耦合的事件驱动系统,发布者(Publisher)和订阅者(Subscriber)通过事件中心(Event Bus或Broker)进行通信,发布者无需知道谁订阅了事件,而订阅者也无需知道事件由谁发布。该模式常用于消息队列、事件系统、异步处理等场景。

2.2. 代码实现

// 事件中心(Event Bus)
class EventBus {
constructor() {
this.subscribers = {}; // 存储所有事件和其对应的订阅者
}
// 订阅事件
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = []; // 如果事件不存在,创建一个新的订阅者列表
}
this.subscribers[event].push(callback); // 将订阅者的回调函数加入列表
}
// 发布事件
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => callback(data)); // 通知所有订阅者
}
}
// 取消订阅
unsubscribe(event, callback) {
if (this.subscribers[event]) {
this.subscribers[event] = this.subscribers[event].filter(cb => cb !== callback); // 移除指定的订阅者
}
}
}
// 创建事件中心
const eventBus = new EventBus();
// 订阅者1
const subscriber1 = (data) => {
console.log('Subscriber 1 received:', data);
};
// 订阅者2
const subscriber2 = (data) => {
console.log('Subscriber 2 received:', data);
};
// 订阅事件
eventBus.subscribe('eventA', subscriber1);
eventBus.subscribe('eventA', subscriber2);
// 发布事件
eventBus.publish('eventA', 'This is event A data');
// Subscriber 1 received: This is event A data
// Subscriber 2 received: This is event A data
// 取消订阅者2的订阅
eventBus.unsubscribe('eventA', subscriber2);
// 再次发布事件
eventBus.publish('eventA', 'This is new event A data');
// Subscriber 1 received: This is new event A data

2.3. 详细注释

  • EventBus(事件中心):作为中介,维护一个事件和订阅者的映射关系。负责发布事件、添加订阅者以及移除订阅者。

  • subscribe:用于订阅某个事件,将订阅者的回调函数加入到对应事件的订阅者列表中。

  • publish:用于发布某个事件,触发该事件的所有订阅者的回调函数。

  • unsubscribe:取消订阅某个事件,移除指定订阅者的回调函数。

2.4. 实际应用

  • 在前端开发中,发布订阅模式常用于事件中心管理事件流,比如在 Vue.js 的 emit和on 中。

  • 消息队列系统(如 RabbitMQ、Kafka)也是发布订阅模式的典型应用。

3. 模板方法模式

3.1. 使用场景

模板方法模式定义了一个操作中的算法骨架,而将一些步骤的实现延迟到子类。常用于固定流程中部分步骤需要定制的场景。在前端中,模板方法模式可用于不同页面之间的结构共享。

3.2. 代码实现

class AbstractClass {
templateMethod() {
this.step1();
this.step2();
this.step3();
}
step1() {
console.log('AbstractClass: Step 1');
}
step2() {
throw new Error('step2 must be implemented by subclass');
}
step3() {
console.log('AbstractClass: Step 3');
}
}
class ConcreteClass extends AbstractClass {
step2() {
console.log('ConcreteClass: Step 2');
}
}
// 使用模板方法模式
const instance = new ConcreteClass();
instance.templateMethod();
// Output:
// AbstractClass: Step 1
// ConcreteClass: Step 2
// AbstractClass: Step 3

3.3. 详细注释

  • AbstractClass:提供算法的骨架,定义了 templateMethod 作为算法的模板方法,具体步骤由子类实现。

  • ConcreteClass:子类实现了模板方法中的具体步骤。

  • 模板方法模式允许子类在不改变算法整体结构的前提下,重新定义算法的某些步骤。

3.4. 实际应用

  • 模板方法模式常用于页面加载逻辑、复杂流程处理等场景,如表单验证步骤、数据处理流程等。

4. 策略模式

4.1. 使用场景

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换使用。在前端开发中,策略模式可以用于处理不同的用户输入、动态选择不同的 UI 渲染逻辑等。

4.2. 代码实现

class StrategyA {
execute() {
console.log('Executing Strategy A');
}
}
class StrategyB {
execute() {
console.log('Executing Strategy B');
}
}
class Context {
setStrategy(strategy) {
this.strategy = strategy;
}
executeStrategy() {
this.strategy.execute();
}
}
// 使用策略模式
const context = new Context();
const strategyA = new StrategyA();
context.setStrategy(strategyA);
context.executeStrategy(); // Executing Strategy A
const strategyB = new StrategyB();
context.setStrategy(strategyB);
context.executeStrategy(); // Executing Strategy B

4.3. 详细注释

  • StrategyA 和 StrategyB:定义了不同的算法实现。

  • Context:上下文类,维护当前策略,并通过 setStrategy 方法动态切换策略。

  • 策略模式允许在运行时根据条件选择不同的算法,避免使用大量条件语句。

4.4. 实际应用

  • 策略模式常用于表单验证、输入处理、动态 UI 渲染等场景。

5. 责任链模式

5.1. 使用场景

责任链模式用于将请求的处理者串联起来,多个对象依次处理请求,直到有对象处理它为止。在前端中,责任链模式常用于事件处理链、表单验证流程等。

5.2. 代码实现

class Handler {
setNext(handler) {
this.nextHandler = handler;
}
handle(request) {
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
return null;
}
}
class ConcreteHandlerA extends Handler {
handle(request) {
if (request === 'A') {
return 'Handled by A';
}
return super.handle(request);
}
}
class ConcreteHandlerB extends Handler {
handle(request) {
if (request === 'B') {
return 'Handled by B';
}
return super.handle(request);
}
}
// 使用责任链模式
const handlerA = new ConcreteHandlerA();
const handlerB = new ConcreteHandlerB();
handlerA.setNext(handlerB);
console.log(handlerA.handle('A')); // Handled by A
console.log(handlerA.handle('B')); // Handled by B

5.3. 详细注释

  • Handler:处理者的基类,提供 setNext 方法来设置下一个处理者。

  • ConcreteHandlerA 和 ConcreteHandlerB:具体处理者,实现了请求处理逻辑。

  • 责任链模式使得多个处理者依次处理请求,避免了请求和处理者之间的紧耦合。

5.4. 实际应用

  • 责任链模式常用于表单验证、事件处理链、权限管理等场景。

6. 中介者模式

6.1. 使用场景

中介者模式用于定义对象间的通信方式,避免直接交互造成的复杂性。在前端中,中介者模式常用于组件之间的通信、事件总线等。

6.2. 代码实现

class Mediator {
notify(sender, event) {
if (event === 'EventA') {
console.log('Mediator reacts to EventA and triggers EventB');
sender.trigger('EventB');
}
}
}
class Component {
constructor(mediator) {
this.mediator = mediator;
}
trigger(event) {
console.log(`Component triggered: ${event}`);
this.mediator.notify(this, event);
}
}
// 使用中介者模式
const mediator = new Mediator();
const component = new Component(mediator);
component.trigger('EventA');
/* Output:
Component triggered: EventA
Mediator reacts to EventA and triggers EventB
Component triggered: EventB
*/

6.3. 详细注释

  • Mediator:中介者类,负责协调不同组件之间的交互。

  • Component:组件类,负责触发事件并通过中介者进行通信。

  • 中介者模式通过集中化的中介者,避免了多个组件之间的复杂依赖关系。

6.4. 实际应用

  • 中介者模式常用于组件通信、消息总线、事件系统等场景。

7. 访问者模式

7.1. 使用场景

访问者模式用于在不改变数据结构的前提下,定义对数据结构中元素的操作。在前端中,访问者模式适用于复杂结构的遍历和操作,如 DOM 树操作等。

7.2. 代码实现

class Element {
accept(visitor) {
visitor.visit(this);
}
}
class ConcreteElementA extends Element {
operationA() {
console.log('Operation A');
}
}
class ConcreteElementB extends Element {
operationB() {
console.log('Operation B');
}
}
class Visitor {
visit(element) {
if (element instanceof ConcreteElementA) {
element.operationA();
} else if (element instanceof ConcreteElementB) {
element.operationB();
}
}
}
// 使用访问者模式
const elements = [new ConcreteElementA(), new ConcreteElementB()];
const visitor = new Visitor();
elements.forEach(element => element.accept(visitor));

7.3. 详细注释

  • Element:元素基类,定义 accept 方法来接受访问者。

  • Visitor:访问者类,提供 visit 方法处理不同的元素类型。

  • 访问者模式允许在不修改数据结构的前提下,动态为结构中的每个元素定义新的操作。

7.4. 实际应用

  • 访问者模式常用于对树形结构、DOM 元素的遍历操作。

8. 命令模式

8.1. 使用场景

命令模式用于将请求封装为对象,从而实现请求的参数化、队列化。在前端中,命令模式适用于实现操作历史、撤销功能等场景。

8.2. 代码实现

class Command {
execute() {
throw new Error('execute method must be implemented');
}
}
class ConcreteCommand extends Command {
constructor(receiver) {
super();
this.receiver = receiver;
}
execute() {
this.receiver.action();
}
}
class Receiver {
action() {
console.log('Receiver action executed');
}
}
class Invoker {
setCommand(command) {
this.command = command;
}
executeCommand() {
this.command.execute();
}
}
// 使用命令模式
const receiver = new Receiver();
const command = new ConcreteCommand(receiver);
const invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand(); // Receiver action executed

8.3. 详细注释

  • Command:命令的基类,定义 execute 方法。

  • ConcreteCommand:具体命令,执行对接收者的操作。

  • Invoker:调用者,负责执行命令。

  • 命令模式通过封装请求,将请求处理逻辑与请求发出者解耦。

8.4. 实际应用

  • 命令模式常用于实现操作历史、撤销重做、宏命令等场景。

9. 解释器模式

9.1. 使用场景

解释器模式用于给定语言的语法表达式,并解析其中的语句。在前端中,解释器模式可用于解析自定义的模板语言、脚本等。

9.2. 代码实现

class Expression {
interpret(context) {
throw new Error('interpret method must be implemented');
}
}
class NumberExpression extends Expression {
constructor(value) {
super();
this.value = value;
}
interpret() {
return this.value;
}
}
class AddExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret() {
return this.left.interpret() + this.right.interpret();
}
}
// 使用解释器模式
const left = new NumberExpression(3);
const right = new NumberExpression(5);
const addExpr = new AddExpression(left, right);
console.log(addExpr.interpret()); // 8

9.3. 详细注释

  • Expression:解释器基类,定义 interpret 方法。

  • NumberExpression 和 AddExpression:具体的解释器,解析数字和加法操作。

  • 解释器模式允许定义一个简单的语言或规则,并通过解释器解析和执行。

9.4. 实际应用

  • 解释器模式常用于处理模板引擎、正则表达式解析等场景。

10. 迭代器模式

10.1. 使用场景

迭代器模式用于顺序访问集合对象的元素,而无需暴露其内部结构。在前端中,迭代器模式常用于遍历数组、集合等数据结构。

10.2. 代码实现

class Iterator {
constructor(collection) {
this.collection = collection;
this.index = 0;
}
hasNext() {
return this.index < this.collection.length;
}
next() {
return this.collection[this.index++];
}
}
// 使用迭代器模式
const collection = [1, 2, 3, 4];
const iterator = new Iterator(collection);
while (iterator.hasNext()) {
console.log(iterator.next()); // 1 2 3 4
}

10.3. 详细注释

  • Iterator:迭代器类,提供 hasNext 和 next 方法来顺序访问集合中的元素。

  • 迭代器模式允许分离集合对象的遍历逻辑,使得遍历和数据结构解耦。

10.4. 实际应用

  • 迭代器模式常用于处理数组、链表、树等数据结构的遍历。

11. 备忘录模式

11.1. 使用场景

备忘录模式用于保存对象的状态,以便在需要时恢复。在前端中,备忘录模式可用于实现撤销功能、保存表单状态等。

11.2. 代码实现

class Memento {
constructor(state) {
this.state = state;
}
getState() {
return this.state;
}
}
class Originator {
setState(state) {
console.log('Setting state to:', state);
this.state = state;
}
saveStateToMemento() {
return new Memento(this.state);
}
getStateFromMemento(memento) {
this.state = memento.getState();
}
}
class Caretaker {
constructor() {
this.mementoList = [];
}
}
// 使用备忘录模式
const originator = new Originator();
const caretaker = new Caretaker();
originator.setState('State 1');
caretaker.add(originator.saveStateToMemento());
originator.setState('State 2');
caretaker.add(originator.saveStateToMemento());
originator.setState('State 3');
console.log('Current State:', originator.state); // Current State: State 3
originator.getStateFromMemento(caretaker.get(0));
console.log('Restored State:', originator.state); // Restored State: State 1

11.3. 详细注释

  • Memento:备忘录类,保存状态。

  • Originator:原始对象,提供保存和恢复状态的方法。

  • Caretaker:管理备忘录列表。

  • 备忘录模式通过保存对象的状态,允许在需要时恢复之前的状态。

11.4. 实际应用

  • 备忘录模式常用于实现撤销功能、表单状态恢复等场景。

12. 状态模式

12.1. 使用场景

状态模式允许对象在内部状态发生改变时,改变其行为。在前端中,状态模式可用于管理复杂的组件状态,如表单验证、UI 状态管理等。

12.2. 代码实现

class State {
handle(context) {
throw new Error('handle method must be implemented');
}
}
class ConcreteStateA extends State {
handle(context) {
console.log('State A, transitioning to State B');
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State {
handle(context) {
console.log('State B, transitioning to State A');
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(); // State A, transitioning to State B
context.request(); // State B, transitioning to State A

12.3. 详细注释

  • State:状态基类,定义 handle 方法。

  • ConcreteStateA 和 ConcreteStateB:具体状态类,实现了状态切换逻辑。

  • Context:上下文类,负责在不同状态下切换并调用状态行为。

  • 状态模式允许对象在状态变化时改变其行为,使得状态切换透明化。

12.4. 实际应用

  • 状态模式常用于处理复杂的状态逻辑,如表单的验证状态、UI 的显示状态等。