Посредник Против Наблюдателя Объектно-Ориентированные Шаблоны Проектирования


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

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

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

8 76

8 ответов:

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

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

источник: dofactory

пример:

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

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

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

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

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

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

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

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

1. Без

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

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

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

2. С

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

посредник

1. Без

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

2. С

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

enter image description here

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

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

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

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

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

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