简体   繁体   English

Mediator Vs Observer面向对象的设计模式

[英]Mediator Vs Observer Object-Oriented Design Patterns

I have been reading the Gang Of Four , in order to solve some of my problems and came across the Mediator pattern. 我一直在阅读四人帮 ,以解决我的一些问题,并遇到了Mediator模式。

I had earlier used Observer in my projects for making some GUI application. 我之前在项目中使用了Observer来制作一些GUI应用程序。 I am a bit confused as I do not find great difference between the two. 我有点困惑,因为我发现两者之间没有太大区别。 I browsed to find the difference but could not find any apt answer for my query. 我浏览找到差异,但找不到任何适合我的查询的答案。

Could some one help me to differentiate between the two with some good example which clearly demarcates the two? 有人可以帮助我区分两者,并用一些明确划分两者的好例子吗?

The Observer pattern: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. Observer模式:定义对象之间的一对多依赖关系,以便当一个对象更改状态时,将自动通知和更新其所有依赖项。

The Mediator pattern: 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. Mediator通过使对象明确地相互引用来促进松散耦合,并且它允许您独立地改变它们的交互。

Source: dofactory 来源: dofactory

Example: 例:

The observer pattern: Class A, can have zero or more observers of type O registered with it. 观察者模式:A类,可以有零个或多个O型观察者注册它。 When something in A is changed it notifies all of the observers. 当A中的某些内容发生变化时,它会通知所有观察者。

The mediator pattern: You have some number of instances of class X (or maybe even several different types:X, Y & Z), and they wish to communicate with each other (but you don't want each to have explicit references to each other), so you create a mediator class M. Each instance of X has a reference to a shared instance of M, through which it can communicate with the other instances of X (or X, Y and Z). 中介模式:你有一些X类实例(或者甚至是几种不同的类型:X,Y和Z),并且它们希望彼此通信(但是你不希望每个实例都有明确的引用因此,您创建一个中介类M.每个X实例都有一个M的共享实例的引用,通过它可以与X(或X,Y和Z)的其他实例进行通信。

In the original book that coined the terms Observer and Mediator, Design Patterns, Elements of Reusable Object-Oriented Software , it says that the Mediator pattern can be implemented by using the observer pattern. 在创造了Observer和Mediator, Design Patterns,可重用面向对象软件的元素这一术语的原始书中,它说可以通过使用观察者模式来实现Mediator模式。 However it can also be implemented by having Colleagues (which are roughly equivalent to the Subjects of the Observer pattern) have a reference to either a Mediator class or a Mediator interface. 但是,也可以通过让同事(大致相当于Observer模式的主题)引用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 is a little more specific, it avoids having classes communicate directly but instead through a mediator. Mediator更具体一点,它避免让课程直接沟通,而是通过调解员沟通。 This helps the Single Responsibility principle by allowing communication to be offloaded to a class that just handles communication. 这有助于单一责任原则,允许将通信卸载到刚刚处理通信的类。

A classic Mediator example is in a GUI, where the naive approach might lead to code on a button click event saying "if the Foo panel is disabled and Bar panel has a label saying "Please enter date" then don't call the server, otherwise go ahead", where with the Mediator pattern it could say "I'm just a button and have no earthly business knowing about the Foo panel and the label on the Bar panel, so I'll just ask my mediator if calling the server is OK right now." 一个典型的Mediator示例位于GUI中,其中天真的方法可能会导致按钮单击事件上的代码说“如果Foo面板被禁用且Bar面板上有标签说”请输入日期“,则不要调用服务器,否则继续“,在Mediator模式中,它可以说”我只是一个按钮,并且没有任何关于Foo面板和Bar面板上的标签的实际业务,所以我只是问我的调解员是否调用服务器现在还可以。“

Or, if Mediator is implemented using the Observer pattern the button would say "Hey, observers (which would include the mediator), my state changed (someone clicked me). Do something about it if you care". 或者,如果Mediator是使用Observer模式实现的,那么按钮会说“嘿,观察者(包括调解员),我的状态发生了变化(有人点击了我)。如果你关心的话,可以做点什么”。 In my example that probably makes less sense then directly referencing the mediator, but in many cases using the Observer pattern to implement Mediator would make sense, and the difference between Observer and Mediator would be more one of intent than a difference in the code itself. 在我的例子中,可能没有意义,然后直接引用中介,但在许多情况下使用Observer模式实现Mediator是有意义的,Observer和Mediator之间的差异将更多的是意图而不是代码本身的差异。

Observer 观察

1. Without 没有

  • Client1 : Hey Subject , when do you change? Client1 :嘿主题 ,你什么时候改变?

  • Client2 : When did you change Subject ? Client2 :你什么时候改变主题 I have not noticed! 我没有注意到!

  • Client3 : I know that Subject has changed. Client3 :我知道Subject已经改变了。

2. With 随着

  • Clients are silent. 客户保持沉默。
  • Some time later ... 一段时间以后 ...
  • Subject : Dear clients , I have changed! 主题 :亲爱的客户 ,我已经改变了!

Mediator 中间人

1. Without 没有

  • Client1 : Hey Taxi1 , take me some where. Client1 :嘿Taxi1 ,带我去哪儿。
  • Client2 : Hey Taxi1 , take me some where. Client2 :嘿Taxi1 ,带我去哪儿。
  • Client1 : Hey Taxi2 , take me some where. Client1 :嘿Taxi2 ,带我去哪儿。
  • Client2 : Hey Taxi2 , take me some where. Client2 :嘿Taxi2 ,带我去哪儿。

2. With 随着

  • Client1 : Hey TaxiCenter , please take me a Taxi . 客户1 :嘿TaxiCenter ,请带我一辆出租车
  • Client2 : Hey TaxiCenter , please take me a Taxi . 客户2 :嘿TaxiCenter ,请带我一辆出租车

These patterns are used in different situations: 这些模式用于不同的情况:

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. 这样,当其中一个子系统发生变化时,您所要做的就是更新中介。

The observer pattern is used when a class wants to allow other classes to register themselves and receive notifications upon events, eg ButtonListener etc. 当一个类想要允许其他类自己注册并在事件上接收通知时使用观察者模式,例如ButtonListener等。

Both of these patterns allow for lesser coupling, but are quite different. 这两种模式都允许较少的耦合,但是完全不同。

Although both of them are used for organised way of telling about state changes, they're slightly different structurally and semantically IMO. 虽然它们都用于有组织地讲述状态变化,但它们在结构和语义上都略有不同。

Observer is used to broadcast a state change of a particular object, from the object itself. Observer用于从对象本身广播特定对象的状态更改。 So the change happens in the central object that is also responsible for signalling it. 因此,变化发生在中心对象中,该中心对象也负责发信号。 However, in Mediator, state change can happen in any object but it's broadcasted from a mediator. 但是,在Mediator中,状态更改可能发生在任何对象中,但它是从调解器广播的。 So there's a difference in the flow. 所以流程有所不同。 But, I don't think this affects our code behaviour. 但是,我不认为这会影响我们的代码行为。 We can use one or another to achieve the same behaviour. 我们可以使用一个或另一个来实现相同的行为。 On the other hand, this difference might have some affects on conceptual understanding of the code. 另一方面,这种差异可能会对代码的概念性理解产生一些影响。

See, the primary purpose of using patterns is rather to create a common language between developers. 请注意,使用模式的主要目的是在开发人员之间创建通用语言。 So, when I see a mediator, I personally understand multiple elements trying to communicate over a single broker/hub to reduce communication noise (or to promote SRP) and each object is equally important in terms of having the ability of signalling a state change. 因此,当我看到调解员时,我个人理解多个元素试图通过单个代理/集线器进行通信以减少通信噪声(或促进SRP),并且每个对象在具有发信号通知状态变化的能力方面同样重要。 For example, think of multiple aircrafts approaching to an airport. 例如,想一下接近机场的多架飞机。 Each should communicate over the pylon (mediator) rather than communicating with each other. 每个人都应该通过塔架(中介)进行沟通,而不是相互沟通。 (Think of 1000 aircrafts communicating with each other when landing - that would be a mess) (想想1000架飞机在着陆时相互通信 - 这将是一团糟)

However, when I see an observer, it means there're some state changes I might be care about and should register/subscribe to listen particular state changes. 但是,当我看到一个观察者时,这意味着我可能会关注一些状态变化,并且应该注册/订阅以监听特定的状态变化。 There's a central object responsible for signalling state changes. 有一个中心对象负责发出状态变化信号。 For example, if I care about a specific airport on my way from A to B, I can register to that airport to catch some events broadcasted like if there's an empty runway or something like that. 例如,如果我在从A到B的途中关心某个特定的机场,我可以在那个机场注册以捕捉一些广播的事件,比如有一条空跑道或类似的东西。

Hope it's clear. 希望很清楚。

@cdc explained the difference in intent excellently. @cdc极好地解释了意图的差异。

I will add some more info on top it. 我将在顶部添加更多信息。

Observer : Enables notification of a event in one object to different set of objects ( instances of different classes) Observer :允许将一个对象中的事件通知给不同的对象集(不同类的实例)

Mediator : Centralize the communication between set of objects, created from a particular class. 介体 :集中从特定类创建的对象集之间的通信。

Structure of Mediator pattern from dofactory : 来自dofactory的Mediator模式的结构:

在此输入图像描述

Mediator : Defines an interface for communication between Colleagues. 调解员 :定义同事之间的通信界面。

Colleague : Is an abstract class, which defines the events to be communicated between Colleagues 同事 :是一个抽象类,它定义了同事之间要传达的事件

ConcreteMediator : Implements cooperative behavior by coordinating Colleague objects and maintains its colleagues ConcreteMediator :通过协调Colleague对象实现协作行为并维护其同事

ConcreteColleague : Implements the notification operations received through Mediator , which has been generated by other Colleague ConcreteColleague :实现通过Mediator收到的通知操作,该操作由其他同事生成

One real world example: 一个现实世界的例子:

You are maintaining a network of computers in Mesh topology. 您正在维护Mesh拓扑中的计算机网络。 If a new computer is added Or existing computer is removed, all other computers in that network should know about these two events. 如果添加了新计算机或删除了现有计算机,则该网络中的所有其他计算机应该知道这两个事件。

Let's see how Mediator pattern fits into it. 让我们看看Mediator模式如何适应它。

Code snippet: 代码段:

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);
    }
}

output: 输出:

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

Explanation: 说明:

  1. Eagle is added to network at first through register event. Eagle首先通过注册事件添加到网络中。 No notifications to any other colleagues since Eagle is the first one. 自Eagle成为第一个以来,没有任何其他同事的通知。
  2. When Ostrich is added to the network, Eagle is notified : Line 1 of output is rendered now. Ostrich添加到网络时, Eagle会收到通知:输出的第1行现在呈现。
  3. When Penguin is added to network, both Eagle and Ostrich have been notified : Line 2 and Line 3 of output is rendered now. Penguin被添加到网络中时, EagleOstrich都会收到通知:输出的第2行和第3行现在呈现。
  4. When Eagle left the network through unregister event, both Ostrich and Penguin have been notified. Eagle通过注销事件离开网络时, OstrichPenguin都已收到通知。 Line 4 and Line 5 of output is rendered now. 现在渲染输出的第4行和第5行。

Lets go by an example: consider you want to build two application: 让我们举一个例子:考虑你想构建两个应用程序:

  1. Chat application. 聊天应用程序
  2. Emergency ambulance operator application. 紧急救护车操作员申请。

mediator 中间人

Building the chat application you will be choosing the mediator design pattern. 构建聊天应用程序,您将选择mediator设计模式。

  • The persons may be joining and leaving the chat at any given time, so it does not make any sense to keep direct reference between two persons chatting. 这些人可能在任何给定时间加入和离开聊天,因此在两个人聊天之间保持直接参考没有任何意义。
  • We still need to facilitate a communication between two persons and allow them have a chat. 我们仍然需要促进两个人之间的沟通,并允许他们聊天。

Why will we prefer the mediator ? 为什么我们更喜欢mediator just have a look at its definition: 看看它的定义:

With the mediator pattern, communication between objects is encapsulated within a mediator object. 使用中介模式,对象之间的通信将封装在中介对象中。 Objects no longer communicate directly with each other, but instead communicate through the mediator. 对象不再直接相互通信,而是通过中介进行通信。 This reduces the dependencies between communicating objects, thereby reducing coupling. 这减少了通信对象之间的依赖性,从而减少了耦合。

How is the magic works? 魔术是如何运作的? First we will create the chat mediator and make the persons objects register to it, so it will have two directional connection with every single person (the person can send message using the chat mediator cause it ha access to it, and the chat mediator will access the received method of the person object cause he also has access to it) 首先,我们将创建聊天中介并使人对象注册到它,因此它将与每个人有两个方向连接(该人可以使用聊天中介发送消息,因为它可以访问它,聊天中介将访问接收到的person对象的方法因为他也可以访问它

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(colton, 'Hello there, nice to meet you');
ronan.send(ronan, 'Nice to meet you to');

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

observer 观察者

Building the 911 call application you will be choosing the observer design pattern. 构建911调用应用程序,您将选择observer设计模式。

  • Each ambulance observer object wishes to be informed when there is an emergency state, so he can drive the address and give help. 当有紧急状态时,每个救护车observer对象都希望得到通知,因此他可以驾驶地址并提供帮助。
  • The emergency operator observable keep reference to each on of the ambulance observers and notify them when help is needed (or generating event). 紧急操作员observable保持对救护车observers每个人的参考,并在需要帮助(或产生事件)时通知他们。

Why will we prefer the observer ? 为什么我们更喜欢observer呢? just have a look at its definition: 看看它的定义:

An object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. 称为主题的对象维护其依赖项列表(称为观察者),并通常通过调用其中一种方法自动通知它们任何状态更改。

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);

The Differences: 差异:

  1. The chat mediator has two way communication between the persons objects (send and receive) wheres the operator observable has only one way communication (It tell the ambulance observer to drive and finish). 聊天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. 聊天mediator可以使人物之间的对象相互作用(即使它不是直接通信),救护车observers只能向操作员注册observable事件。
  3. Each person object has a reference to the chat mediator , and also the chat mediator keep reference to the every one of the persons. 每个人对象必须聊天参考mediator ,也聊天mediator保持参照人的每一个。 Wheres the ambulance observer does not keep reference to the operator observable , only the operator observable keep reference to every ambulance observer . 当救护车observer没有参考操作员observable ,只有操作员observable到的是对每个救护车observer参考。

How About this explanation Technically both Observer and Mediator are the same and are used to provide decoupled way for component communication, but usage is different. 如何解释这个解释从技术上讲,Observer和Mediator都是相同的,用于为组件通信提供解耦方式,但用法不同。

While obeserver notifies subscribed components about state changes (creation of new db record, for instance), the mediator commands registered components to do something related to business logic flow (sending email to user for password reset). obeserver 通知 订阅组件有关状态更改(例如,创建新的db记录)时, mediator 命令 注册组件执行与业务逻辑流相关的操作(向用户发送电子邮件以进行密码重置)。

Observer 观察

  • Notification consumers are responsible to subscribe in order to receive notifications 通知消费者有责任订阅以接收通知
  • Notification processing is not part of business flow 通知处理不是业务流程的一部分

Mediator 中间人

  • Explicit registration required to connect "publisher" and "consumers" 连接“发布者”和“消费者”所需的明确注册
  • Notification processing is part of specific business flow 通知处理是特定业务流程的一部分

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM