Объектно-ориентированные шаблоны проектирования медиаторов Vs Observer

Я читал Gang Of Four, чтобы решить некоторые из моих проблем и наткнулся на Посредник.

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

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

Ответ 1

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

Схема посредника: Определите объект, который инкапсулирует взаимодействие объекта. Посредник способствует свободному соединению, не допуская прямого доступа объектов друг к другу, и позволяет вам независимо изменять их взаимодействие.

Источник: dofactory

Пример:

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

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

Ответ 2

В оригинальной книге, в которой были использованы термины Observer и Mediator, Design Patterns, Elements of Многоразовое объектно-ориентированное программное обеспечение, говорится, что шаблон Mediator может быть реализован с использованием шаблона наблюдателя. Однако это также можно реализовать, если Коллеги (которые примерно эквивалентны объектам шаблона Observer) имеют ссылку на класс посредника или интерфейс посредника.

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

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

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

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

Ответ 3

Observer

1. Без

  • Клиент1: Эй Тема, когда вы меняете?

  • Клиент2. Когда вы изменили Тема? Я не заметил!

  • Клиент3. Я знаю, что Тема изменилась.

2. С

  • Клиенты не работают.
  • Через некоторое время...
  • Тема: Уважаемые клиенты, я изменился!

Mediator

1. Без

  • Клиент1: привет Taxi1, возьмите меня где-нибудь.
  • Клиент2: привет Taxi1, возьмите меня где-нибудь.
  • Клиент1: Эй Taxi2, возьмите меня куда.
  • Клиент2: Эй Taxi2, возьмите меня куда.

2. С

  • Клиент1: Эй TaxiCenter, пожалуйста, возьмите Taxi.
  • Клиент2: привет TaxiCenter, пожалуйста, примите меня Taxi.

Ответ 4

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

Я добавлю еще немного информации об этом.

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

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

Структура шаблона посредника из dofactory:

введите описание изображения здесь

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

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

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

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

Один пример в реальном мире:

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

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

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

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

Пояснение:

  • Eagle добавляется в сеть сначала через событие регистрации. Никаких уведомлений другим коллегам, так как Eagle является первым.
  • Когда Ostrich добавляется в сеть, Eagle уведомляется: теперь выводится строка 1 вывода.
  • Когда пингвин добавлен в сеть, оба Eagle и Ostrich были уведомлены: теперь отображаются строка 2 и строка 3.
  • Когда Орел покинул сеть через незарегистрированное событие, оба страуса и пингвина были уведомлены. Теперь отображаются строки 4 и строка 5.

Ответ 7

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

  1. Приложение чата.
  2. Приложение оператора скорой помощи.

медиатор

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

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

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

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

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

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. Каждый объект объекта имеет ссылку на mediator чата, а также mediator чата поддерживает ссылку на каждого из лиц. Наблюдая за тем, чтобы observer скорой помощи не обращал внимание на observable оператор, только observable оператор сохраняет ссылку на каждого observer скорой помощи.

Ответ 8

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

В то время как obeserver уведомляет подписанные компоненты о состоянии изменений (например, создание новой записи db), mediator управляет зарегистрированными компонентами, чтобы что-то делать с потоком бизнес-логики (отправка электронной почты пользователю для сброса пароля).

наблюдатель

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

медиатор

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