调停者与观察者的面向对象设计模式

我一直在阅读 四人帮(Gang Of Four),为了解决我的一些问题,遇到了 调解员模式。

我之前在我的项目中使用了 观察者来制作一些 GUI 应用程序。我有点困惑,因为我没有发现这两者之间有很大的区别。我浏览寻找差异,但找不到任何适合我的问题的答案。

有没有人能用一些好的例子来帮助我区分这两者?

34797 次浏览

这些模式在不同的情况下使用:

The mediator pattern is used when you have two sub-systems with some dependency and one of them is due for a change, and since you might not want to change the system that depends on the other, you may want to introduce a mediator which will decouple the dependency between them. That way, when one of the sub-systems changes, all you have to do is to update the mediator.

当一个类希望允许其他类注册自己并接收事件通知时,就会使用这个观察者模式,例如 ButtonListener 等。

这两种模式都允许较少的耦合,但是完全不同。

观察者模式: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

调解员模式: Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Source: 工厂

例如:

观察者模式: 类 A,可以有零个或多个注册为 O 类型的观察者。当 A 中的某些内容发生更改时,它会通知所有的观察者。

The mediator pattern: 你有一些类 x 的数量(或者甚至是几个不同的类型: x、 Y 和 Z) ,它们希望彼此通信(但是你不希望每个类都有明确的引用) ,所以你创建了一个中介类 m。每个 x 的实例都有一个对共享实例 M 的引用,通过这个实例它可以与其他类型的 x (或者 x、 Y 和 Z)通信。

在创造了观察者和中介这两个术语的原著中,Design Patterns, Elements of Reusable Object-Oriented Software指出中介模式可以通过使用观察者模式来实现。然而,它也可以通过使 Colleague (大致相当于观察者模式的 Subject)具有对 Mediator 类或 Mediator 接口的引用来实现。

There are many cases when you would want to use the observer pattern, they key is that an object should not know what other objects are observing it's state.

中介更具体一些,它避免了类直接通信,而是通过中介进行通信。通过允许将通信卸载到仅处理通信的类,这有助于实现单一责任原则。

一个典型的 Mediator 例子是在图形用户界面中,这种幼稚的方法可能会导致按钮点击事件的代码说“如果 Foo 面板被禁用,并且 Bar 面板上有一个标签说“请输入日期”,那么不要调用服务器,否则继续”,而 Mediator 模式可能会说“我只是一个按钮,对 Foo 面板和 Bar 面板上的标签一无所知,所以我只会问我的仲裁者,现在调用服务器是否可以。”

或者,如果 Mediator 是使用观察者模式实现的,按钮会说“嘿,观察者(包括中介) ,我的状态改变了(有人点击了我)。如果你在乎,就做点什么吧。”。在我的例子中,这可能没有直接引用中介那么有意义,但是在很多情况下,使用观察者模式来实现中介是有意义的,观察者和中介之间的区别更多的是意图而不是代码本身的区别。

观察者

1. 无

  • 客户1 : 嘿 主题,你什么时候换?

  • 客户2 : 你什么时候改变了 主题? 我没有注意到!

  • 客户3 : 我知道 主题已经改变了。

2. 与

  • 客户保持沉默。
  • 过了一段时间。
  • 主题 : 亲爱的 clients,我变了!

调解员

1. 无

  • 客户1 : 嘿 出租车1,带我去一些地方。
  • 客户2 : 嘿 Taxi1,带我去一些地方。
  • 客户1 : 嘿 出租车2,带我去一些地方。
  • 客户2 : 嘿 Taxi2,带我去一些地方。

2. 与

  • Client1: Hey 出租车中心, please take me a 出租车.
  • 客户2 : 嘿,TaxiCenter,请给我一个 出租车

@ cdc 很好地解释了意图上的差异。

我会在上面添加更多的信息。

Observer : 允许将一个对象中的事件通知给不同的对象集(不同类的实例)

Mediator : 集中从特定类创建的一组对象之间的通信。

Structure of Mediator pattern from 工厂:

enter image description here

Mediator : 定义用于同事间通信的接口。

Colleague: Is an abstract class, which defines the events to be communicated between Colleagues

ConcreteMediator : 通过协调 同事对象并维护其同事来实现合作行为

ConcreteColleague: Implements the notification operations received through Mediator, which has been generated by other Colleague

现实生活中的一个例子:

您正在使用 Mesh拓扑维护计算机网络。如果添加了新计算机或删除了现有计算机,则该网络中的所有其他计算机都应该知道这两个事件。

让我们看看调解人模式是如何与之匹配的。

代码片段:

import java.util.List;
import java.util.ArrayList;


/* Define the contract for communication between Colleagues.
Implementation is left to ConcreteMediator */
interface Mediator{
public void register(Colleague colleague);
public void unregister(Colleague colleague);
}
/* Define the contract for notification events from Mediator.
Implementation is left to ConcreteColleague
*/
abstract class Colleague{
private Mediator mediator;
private String name;


public Colleague(Mediator mediator,String name){
this.mediator = mediator;
this.name = name;
}
public String toString(){
return name;
}
public abstract void receiveRegisterNotification(Colleague colleague);
public abstract void receiveUnRegisterNotification(Colleague colleague);
}
/*  Process notification event raised by other Colleague through Mediator.
*/
class ComputerColleague extends Colleague {
private Mediator mediator;


public ComputerColleague(Mediator mediator,String name){
super(mediator,name);
}
public  void receiveRegisterNotification(Colleague colleague){
System.out.println("New Computer register event with name:"+colleague+
": received @"+this);
// Send further messages to this new Colleague from now onwards
}
public  void receiveUnRegisterNotification(Colleague colleague){
System.out.println("Computer left unregister event with name:"+colleague+
":received @"+this);
// Do not send further messages to this Colleague from now onwards
}
}
/* Act as a central hub for communication between different Colleagues.
Notifies all Concrete Colleagues on occurrence of an event
*/
class NetworkMediator implements Mediator{
List<Colleague> colleagues = new ArrayList<Colleague>();


public NetworkMediator(){


}


public void register(Colleague colleague){
colleagues.add(colleague);
for (Colleague other : colleagues){
if ( other != colleague){
other.receiveRegisterNotification(colleague);
}
}
}
public void unregister(Colleague colleague){
colleagues.remove(colleague);
for (Colleague other : colleagues){
other.receiveUnRegisterNotification(colleague);
}
}
}


public class MediatorPatternDemo{
public static void main(String args[]){
Mediator mediator = new NetworkMediator();
ComputerColleague colleague1 = new ComputerColleague(mediator,"Eagle");
ComputerColleague colleague2 = new ComputerColleague(mediator,"Ostrich");
ComputerColleague colleague3 = new ComputerColleague(mediator,"Penguin");
mediator.register(colleague1);
mediator.register(colleague2);
mediator.register(colleague3);
mediator.unregister(colleague1);
}
}

产出:

New Computer register event with name:Ostrich: received @Eagle
New Computer register event with name:Penguin: received @Eagle
New Computer register event with name:Penguin: received @Ostrich
Computer left unregister event with name:Eagle:received @Ostrich
Computer left unregister event with name:Eagle:received @Penguin

说明:

  1. Eagle is added to network at first through register event. No notifications to any other colleagues since Eagle is the first one.
  2. 鸵鸟添加到网络时,会通知 老鹰: 现在呈现输出的第1行。
  3. When 企鹅 is added to network, both 老鹰 and 鸵鸟 have been notified : Line 2 and Line 3 of output is rendered now.
  4. When Eagle left the network through unregister event, both 鸵鸟 and 企鹅 have been notified. Line 4 and Line 5 of output is rendered now.

虽然它们都用于有组织的方式告诉状态变化,但它们在结构和语义上略有不同。

观察器用于从对象本身广播特定对象的状态更改。因此,变化发生在中心对象,它也负责发出信号。然而,在中介中,状态更改可以发生在任何对象中,但是它是通过中介进行广播的。所以流程是不同的。但是,我不认为这会影响我们的代码行为。我们可以用这个或那个来实现同样的行为。另一方面,这种差异可能会对代码的概念理解产生一些影响。

看,使用模式的主要目的是在开发人员之间创建一种共同的语言。因此,当我看到一个中介时,我个人理解多个元素试图通过一个代理/中心进行通信,以减少通信噪音(或促进 SRP) ,每个对象在发出状态更改信号的能力方面同样重要。例如,想象多架飞机接近一个机场。每个人都应该通过桥塔(中间人)进行沟通,而不是彼此之间进行沟通。(想象一下1000架飞机在着陆时相互通信——那将是一团糟)

但是,当我看到一个观察者时,它意味着有一些我可能关心的状态更改,并且应该注册/订阅以监听特定的状态更改。有一个负责发送状态更改信号的中心对象。例如,如果我在从 A 到 B 的路上关心一个特定的机场,我可以登记到那个机场去观看一些广播的事件,比如是否有一条空跑道或者类似的东西。

希望没人。

这个解释怎么样 观察者和中介者在技术上是相同的,用于为组件通信提供解耦方式,但用法不同。

obeserver 通知 订阅组件的状态变化(例如创建新的数据库记录) ,mediator 命令 注册的组件做一些与业务逻辑流相关的事情(发送电子邮件给用户进行密码重置)。

观察者

  • 通知使用者负责订阅以接收通知
  • 通知处理不是业务流程的一部分

调解员

  • 连接“发布者”和“消费者”所需的显式注册
  • 通知处理是特定业务流程的一部分

让我们举一个例子: 假设您想要构建两个应用程序:

  1. 聊天软件。
  2. Emergency ambulance operator application.

调解员

构建聊天应用程序时,您将选择 mediator设计模式。

  • 人们可能在任何时间加入和离开聊天,所以保持两个人之间的直接联系是没有意义的。
  • 我们仍然需要促进两个人之间的沟通,并允许他们进行交谈。

Why will we prefer the mediator? just have a look at its definition:

使用中介模式,对象之间的通信是 封装在中介对象中。对象不再通信 直接交流,而不是通过 这减少了通信对象之间的依赖关系, thereby reducing coupling.

魔法是怎么起作用的?首先我们将创建聊天中介,并使人对象注册到它,这样它将与每个人有两个方向的连接(人可以使用聊天中介发送消息,因为它有访问它的权限,聊天中介将访问人对象的接收方法,因为他也有访问它的权限)

function Person(name) {
let self = this;
this._name = name;
this._chat = null;


this._receive(from, message) {
console.log("{0}: '{1}'".format(from.name(), message));
}
this._send(to, message) {
this._chat.message(this, to, message);
}
return {
receive: (from, message) => { self._receive(from, message) },
send: (to, message) => { self._send(to, message) },
initChat: (chat) => { this._chat = chat; },
name: () => { return this._name; }
}
}




function ChatMediator() {
let self = this;
this._persons = [];


return {
message: function (from, to, message) {
if (self._persons.indexOf(to) > -1) {
self._persons[to].receive(from, message);
}
},
register: function (person) {
person.initChat(self);
self._persons.push(person);
}
unRegister: function (person) {
person.initChat(null);
delete self._persons[person.name()];
}
}
};


//Usage:
let chat = new ChatMediator();


let colton = new Person('Colton');
let ronan = new Person('Ronan');


chat.register(colton);
chat.register(ronan);


colton.send(ronan, 'Hello there, nice to meet you');
ronan.send(colton, 'Nice to meet you to');


colton.send(ronan, 'Goodbye!');
chat.unRegister(colton);

观察者

构建911呼叫应用程序时,您将选择 observer设计模式。

  • 每个救护车 observer对象希望被告知当有一个紧急状态,所以他可以驱动的地址和提供帮助。
  • 应急操作员 observable保持参考每辆救护车 observers,并通知他们,当需要帮助(或发生事件)。

为什么我们更喜欢 observer? 看看它的定义:

An object, called the subject, maintains a list of its dependents, 调用观察员,并自动通知他们任何状态 通常通过调用它们的一个方法来更改。

function AmbulanceObserver(name) {
let self = this;
this._name = name;
this._send(address) {
console.log(this._name + ' has been sent to the address: ' + address);
}
return {
send: (address) => { self._send(address) },
name: () => { return this._name; }
}
}




function OperatorObservable() {
let self = this;
this._ambulances = [];


return {
send: function (ambulance, address) {
if (self._ambulances.indexOf(ambulance) > -1) {
self._ambulances[ambulance].send(address);
}
},
register: function (ambulance) {
self._ambulances.push(ambulance);
}
unRegister: function (ambulance) {
delete self._ambulances[ambulance.name()];
}
}
};


//Usage:
let operator = new OperatorObservable();


let amb111 = new AmbulanceObserver('111');
let amb112 = new AmbulanceObserver('112');


operator.register(amb111);
operator.register(amb112);


operator.send(amb111, '27010 La Sierra Lane Austin, MN 000');
operator.unRegister(amb111);


operator.send(amb112, '97011 La Sierra Lane Austin, BN 111');
operator.unRegister(amb112);

区别:

  1. 聊天 mediator在人物对象(发送和接收)之间有双向通信,其中操作者 observable只有单向通信(它告诉救护车 observer开车和完成)。
  2. The chat mediator can make the persons objects interact between them (even if it not a direct communication), the ambulances observers only registers to the operator observable events.
  3. 每个人物对象都有一个对聊天 mediator的引用,而且聊天 mediator保持对每个人物的引用。如果救护车 observer没有参考操作员 observable,只有操作员 observable参考每辆救护车 observer