Медиатор Vs Observer Объектно-Ориентированные Шаблоны Проектирования

Я читал Банда Из Четырех, чтобы решить некоторые из моих проблем и наткнулся на посредник узор.

Я раньше использовал Обозреватель в моих проектах для создания некоторых приложений GUI. Я немного смущен, так как не нахожу большой разницы между ними. Я просмотрел, чтобы найти разницу, но не смог найти подходящего ответа на мой вопрос.

может кто-нибудь помочь мне отличить между двумя с каким-то хорошим примером, который четко разграничивает два?

8 ответов


шаблон наблюдатель : Определяет зависимость "один ко многим" между объектами, так что при изменении состояния одного объекта все его иждивенцы уведомляются и обновляются автоматически.

медиатор шаблон: Определите объект, который инкапсулирует способ взаимодействия набора объектов. Медиатор способствует свободной связи, удерживая объекты от обращения друг к другу явно, и это позволяет варьировать их взаимодействие независимо.

источник: dofactory

пример:

шаблон наблюдатель : Класс A, может иметь ноль или более наблюдателей типа O, зарегистрированных с ним. Когда что-то в A изменяется, он уведомляет всех наблюдателей.

медиатор шаблон: У вас есть несколько экземпляров класса X (или, возможно, даже несколько разных типов: X, Y & Z), и они хотят общаться друг с другом (но вы не хотите, чтобы у каждого были явные ссылки друг на друга), поэтому вы создаете класс-посредник M. каждый экземпляр X имеет ссылку на общий экземпляр M, через который он может взаимодействовать с другими экземплярами X (или X, Y и Z).


в оригинальной книге, которая придумала термины наблюдатель и посредник,шаблоны проектирования, элементы объектно-ориентированного проектирования, Он говорит, что шаблон посредника может быть реализован с помощью шаблона наблюдателя. Однако он также может быть реализован, если коллеги (которые примерно эквивалентны субъектам шаблона наблюдателя) имеют ссылку либо на класс медиатора, либо на интерфейс медиатора.

есть много случаев, когда вы хотите используйте шаблон наблюдателя, они ключ в том, что объект не должен знать, какие другие объекты наблюдают за его состоянием.

медиатор немного более конкретный, он избегает того, чтобы классы общались напрямую, но вместо этого через посредника. Это помогает принципу единой ответственности, позволяя выгружать связь в класс, который просто обрабатывает связь.

классический пример медиатора находится в GUI, где наивный подход может привести к коду при нажатии кнопки событие, говорящее: "если панель Foo отключена, а панель бара имеет ярлык с надписью "Пожалуйста, введите дату", тогда не звоните на сервер, иначе продолжайте", где с шаблоном посредника он может сказать: "я просто кнопка и не имею никакого земного бизнеса, зная о панели Foo и ярлыке на панели бара, поэтому я просто спрошу своего посредника, если вызов сервера в порядке прямо сейчас."

или, если медиатор реализован с использованием шаблона наблюдателя, кнопка скажет: "Эй, наблюдатели (которые включите посредника), мое состояние изменилось (кто-то щелкнул меня). Сделай что-нибудь, если тебе не все равно". В моем примере это, вероятно, имеет меньше смысла, чем прямая ссылка на медиатора, но во многих случаях использование шаблона наблюдателя для реализации медиатора имело бы смысл, и разница между наблюдателем и медиатором была бы больше намерением, чем разница в самом коде.


Обозреватель

1. Без

  • Client1: Привет теме, когда вы изменяете?

  • Client2: когда вы изменились теме? Я не заметил!

  • Client3: Я знаю, что теме изменилось.

2. С

  • клиенты несколько тихий.
  • некоторое время спустя ...
  • теме: уважаемый клиенты, я изменился!

посредник

1. Без

  • Client1: Привет Taxi1, отведи меня куда-нибудь.
  • Client2: Привет Taxi1, отведи меня куда-нибудь.
  • Client1: Привет Taxi2 возьмите меня некоторые где.
  • Client2: Привет Taxi2, отведи меня куда-нибудь.

2. С

  • Client1: Привет TaxiCenter, пожалуйста, возьми меня такси.
  • Client2: Привет TaxiCenter, пожалуйста, возьми меня такси.

эти шаблоны используются в разных ситуациях:

шаблон посредника используется, когда у вас есть две подсистемы с некоторой зависимостью, и одна из них должна измениться, и поскольку вы не можете изменить систему, которая зависит от другой, вы можете ввести посредника, который будет отделять зависимость между ними. Таким образом, когда одна из подсистем изменяется, все, что вам нужно сделать, это обновить посредника.

используется шаблон наблюдателя когда класс хочет разрешить другим классам регистрироваться и получать уведомления о событиях, e. г. ButtonListener etc.

оба этих шаблона допускают меньшее сцепление, но совершенно разные.


хотя оба они используются для организованного способа рассказать об изменениях состояния, они немного отличаются структурно и семантически.

Observer используется для трансляции изменения состояния конкретного объекта из самого объекта. Таким образом, изменение происходит в Центральном объекте, который также отвечает за его сигнализацию. Однако в медиаторе изменение состояния может произойти в любом объекте, но оно транслируется от медиатора. Так что есть разница в потоке. Но Я ... не думаю, что это влияет на наше поведение кода. Мы можем использовать то или другое для достижения одного и того же поведения. С другой стороны, это различие может иметь некоторые последствия для концептуального понимания кода.

см., основная цель шаблонов - скорее создать общий язык между разработчиками. Итак, когда я вижу посредника, я лично понимаю, что несколько элементов пытаются общаться через одного брокера / концентратора для снижения шума связи (или продвижения SRP) , и каждый объект не менее важно с точки зрения способности сигнализировать об изменении состояния. Например, подумайте о нескольких самолетах, приближающихся к аэропорту. Каждый должен общаться через пилон (посредника), а не общаться друг с другом. (Подумайте о 1000 самолетов, сообщающихся друг с другом при посадке)

однако, когда я вижу наблюдателя, это означает, что есть некоторые изменения состояния, о которых я мог бы заботиться, и должен зарегистрироваться/подписаться на прослушивание определенных изменений состояния. Есть центральный объект, отвечающий за сигнализацию изменений состояния. Например, если я забочусь о конкретном аэропорту по пути из А В б, я могу зарегистрироваться в этом аэропорту, чтобы поймать некоторые события, транслируемые, например, если есть пустая взлетно-посадочная полоса или что-то в этом роде.

надеюсь, это понятно.


@cdc превосходно объяснил разницу в намерениях.

Я добавлю еще немного информации сверху.

Обозреватель: включает уведомление о событии в одном объекте для разных наборов объектов (экземпляров разных классов)

посредник: централизация связи между множеством объектов, созданных из определенного класса.

структура картины посредника от dofactory:

enter image description here

посредник: определяет интерфейс для связи между коллегами.

коллега: абстрактный класс, который определяет события, которые должны быть переданы между коллегами

ConcreteMediator: реализует кооперативное поведение, координируя коллега объекты и поддерживает его коллеги!--3-->

ConcreteColleague: реализует операции уведомления, полученные через посредник, который был сгенерирован другим коллега

один реальный пример:

вы поддерживаете сеть компьютеров в сетки топологии. Если новый компьютер добавлен или существующий компьютер удален, все остальные компьютеры в этой сети должны знать о эти два события.

давайте посмотрим, как шаблон медиатора вписывается в него.

фрагмент кода:

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. Орел добавляется в сеть сначала через событие register. Никаких уведомлений другим коллегам, так как Eagle является первым.
  2. , когда страусиная добавляется в сеть, Орел уведомлено : строка 1 вывода теперь передано.
  3. , когда Пингвин добавляется в сеть, как Орел и страусиная были уведомлены: строка 2 и строка 3 вывода отображаются сейчас.
  4. , когда Орел вышел из сети через событие unregister, оба страусиная и Пингвин были уведомлены. Строка 4 и строка 5 вывода отображаются сейчас.

Как насчет такого объяснения Технически как наблюдатель, так и медиатор одинаковы и используются для обеспечения развязанного пути для компонентной связи, но использование отличается.

пока obeserver сообщает подписка компоненты об изменениях состояния (например, создание новой записи БД),mediator команды зарегистрированы компоненты, чтобы сделать что-то связанное с потоком бизнес-логики (отправка электронной почты для пароля сброс.)

Обозреватель

  • потребители уведомлений несут ответственность за подписку, чтобы получать уведомления
  • обработка уведомлений не является частью бизнес-потока

посредник

  • явная регистрация требуется для подключения "издателя"и " потребителей"
  • обработка уведомлений является частью конкретного бизнес-потока

давайте рассмотрим пример: рассмотрим, что вы хотите построить два приложения:

  1. приложения разговора.
  2. применение оператора скорой помощи.

посредник

создание приложения чата вы будете выбирать mediator шаблон дизайна.

  • люди могут присоединяться и покидать чат в любой момент времени, поэтому нет никакого смысла держать прямую ссылку между двумя люди болтают.
  • нам все еще нужно облегчить общение между двумя людьми и позволить им общаться.

почему мы предпочитаем mediator? просто взгляните на его определение:

С картиной посредника, сообщение между объектами инкапсулируется в объект-посредник. Объекты больше не взаимодействуют непосредственно друг с другом, но вместо этого общаться через посредник. Это уменьшает зависимости между объектами общения , таким образом уменьшающ соединение.

как работает магия? Сначала мы создадим медиатор чата и зарегистрируем объекты persons, поэтому он будет иметь двухнаправленное соединение с каждым человеком (человек может отправлять сообщение с помощью медиатора чата, потому что он имеет доступ к нему, и медиатор чата получит доступ к полученному методу объекта 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);

обозреватель

построение приложения вызова 911 вы будете выбирать observer шаблон дизайна.

  • каждый скорой помощи observer объект хочет быть проинформирован, когда есть чрезвычайное положение, поэтому он может управлять адресом и оказывать помощь.
  • аварийный оператор observable сохранить ссылку на каждый из скорой помощи observers и уведомлять их, когда требуется помощь (или создание событие.)

почему мы предпочитаем observer? просто взгляните на его определение:

объект, называемый субъектом, ведет список своих иждивенцев, вызываются наблюдатели и автоматически уведомляют их о любом государстве изменения, как правило, путем вызова их методов.

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. чат mediator может заставить объекты людей взаимодействовать между собой (даже если это не прямая связь), машины скорой помощи observers регистрируется только для оператора observable событий.
  3. каждый объект person имеет ссылку на чат mediator, а также чат mediator сохранить ссылку на каждого из людей. Где скорая observer тут не держите ссылку на оператора observable, только оператор observable держите ссылку на каждую скорую observer.