JavaScript 中的中介者模式(十四)

40 阅读4分钟

中介者模式(Mediator Pattern)是一种行为型设计模式,用于减少对象之间的复杂通信。它通过一个中介者对象来处理对象之间的交互,使得对象之间的依赖关系更加松散。中介者模式特别适合用于处理多个对象之间的协作,避免了对象之间的直接引用,从而减少了系统的复杂性。本文将深入探讨中介者模式的概念、实现方式以及在 JavaScript 中的应用实例。

什么是中介者模式?

中介者模式涉及以下主要角色:

  1. 中介者接口(Mediator):定义中介者需要实现的方法,用于与各个组件进行交互。
  2. 具体中介者(Concrete Mediator):实现中介者接口,维护各个组件的引用,并定义其之间的交互。
  3. 组件接口(Colleague):定义与中介者进行交互的方法。
  4. 具体组件(Concrete Colleague):实现组件接口,向中介者发送和接收消息。

中介者模式的优缺点

优点
  1. 降低组件之间的耦合:通过引入中介者,组件之间不再直接引用,从而降低了耦合度。
  2. 集中控制交互:中介者集中处理对象之间的交互逻辑,易于管理和维护。
  3. 便于扩展:添加新组件时,只需修改中介者的代码,而无需修改组件之间的交互逻辑。
缺点
  1. 中介者成为复杂的类:随着系统的复杂性增加,中介者可能变得难以维护。
  2. 不利于组件的重用:由于组件依赖于中介者,可能会影响其重用性。

中介者模式的实现

1. 基本实现

下面是一个简单的中介者模式的实现示例,展示如何通过中介者管理多个组件(如用户和聊天室)。

// 中介者接口
class ChatRoomMediator {
  register(user) {
    throw new Error('This method should be overridden!');
  }

  send(message, user) {
    throw new Error('This method should be overridden!');
  }
}

// 具体中介者:聊天房间
class ChatRoom extends ChatRoomMediator {
  constructor() {
    this.users = {};
  }

  register(user) {
    this.users[user.name] = user;
    user.setMediator(this);
  }

  send(message, user) {
    for (const username in this.users) {
      if (this.users[username] !== user) {
        this.users[username].receive(message);
      }
    }
  }
}

// 组件接口
class User {
  setMediator(mediator) {
    throw new Error('This method should be overridden!');
  }

  send(message) {
    throw new Error('This method should be overridden!');
  }

  receive(message) {
    throw new Error('This method should be overridden!');
  }
}

// 具体组件:用户
class ChatUser extends User {
  constructor(name) {
    super();
    this.name = name;
    this.mediator = null;
  }

  setMediator(mediator) {
    this.mediator = mediator;
  }

  send(message) {
    console.log(`${this.name} sends: ${message}`);
    this.mediator.send(message, this);
  }

  receive(message) {
    console.log(`${this.name} receives: ${message}`);
  }
}

// 使用示例
const chatRoom = new ChatRoom();

const alice = new ChatUser('Alice');
const bob = new ChatUser('Bob');

chatRoom.register(alice);
chatRoom.register(bob);

alice.send('Hello, everyone!'); // Alice sends: Hello, everyone!
bob.send('Hi, Alice!');           // Bob sends: Hi, Alice!

在这个示例中,ChatRoomMediator 是中介者接口,定义了注册用户和发送消息的方法。ChatRoom 是具体中介者,管理用户的注册和消息的传递。User 是组件接口,ChatUser 是具体组件,实现了发送和接收消息的方法。

2. 在表单管理中的中介者模式

中介者模式还可以应用于表单管理,以集中处理表单字段之间的交互。下面是一个简单的示例。

// 中介者接口
class FormMediator {
  register(field) {
    throw new Error('This method should be overridden!');
  }

  notify(field) {
    throw new Error('This method should be overridden!');
  }
}

// 具体中介者:表单
class Form extends FormMediator {
  constructor() {
    this.fields = [];
  }

  register(field) {
    this.fields.push(field);
    field.setMediator(this);
  }

  notify(field) {
    console.log(`Field ${field.name} has changed to: ${field.value}`);
  }
}

// 组件接口
class FormField {
  setMediator(mediator) {
    throw new Error('This method should be overridden!');
  }

  setValue(value) {
    throw new Error('This method should be overridden!');
  }
}

// 具体组件:文本输入框
class TextInput extends FormField {
  constructor(name) {
    super();
    this.name = name;
    this.value = '';
    this.mediator = null;
  }

  setMediator(mediator) {
    this.mediator = mediator;
  }

  setValue(value) {
    this.value = value;
    this.mediator.notify(this);
  }
}

// 使用示例
const form = new Form();

const usernameField = new TextInput('Username');
const passwordField = new TextInput('Password');

form.register(usernameField);
form.register(passwordField);

usernameField.setValue('Alice'); // Field Username has changed to: Alice
passwordField.setValue('123456'); // Field Password has changed to: 123456

在这个示例中,FormMediator 是中介者接口,定义了注册字段和通知变更的方法。Form 是具体中介者,管理表单字段的注册和变更通知。FormField 是组件接口,TextInput 是具体组件,实现了设置值和通知中介者的方法。

何时使用中介者模式?

中介者模式适合以下场景:

  • 需要减少多个对象之间的复杂交互时。
  • 需要集中处理对象之间的通信逻辑时。
  • 需要降低对象之间的耦合度时。
  • 需要在添加新组件时,不影响现有组件的功能时。

总结

中介者模式是一种有效的设计模式,可以帮助我们降低系统的复杂性,通过集中处理对象之间的交互逻辑来提高代码的可维护性。在 JavaScript 开发中,中介者模式适用于处理复杂的组件交互和多个对象之间的协作场景。

在下一篇文章中,我们将探讨 JavaScript 中的桥接模式,敬请期待!