Mediator Vs Observer Nesneye Yönelik Tasarım Kalıpları


95

Bazı sorunlarımı çözmek için Gang Of Four'u okuyordum ve Arabulucu modeliyle karşılaştım.

Daha önce bazı GUI uygulamaları yapmak için projelerimde Observer kullanmıştım . İkisi arasında büyük bir fark bulamadığım için biraz kafam karıştı. Farkı bulmak için göz attım ancak sorgum için uygun bir cevap bulamadım.

Biri, ikisini açıkça ayıran iyi bir örnekle ikisi arasında ayrım yapmama yardım edebilir mi?


5
Bu soruyu sitesine taşıma isteğim Programmers.StackExchangereddedildi, ancak yanıtla ilgilendiğim için orada benzer bir gönderi yaptım. Bazı cevapları ilginç bulabilirsin. :)
Rachel

JavaScript örnekleri için, benzer bir soruya verdiğim cevaba bakabilirsiniz .
Alex Pakka

Orijinal GoF kitabı ChangeManager, kullanılan Observermodel için bir örnek vererek, uygulama bölümü altında 8 numaralı noktayı ele alır Mediator. görmek; paginas.fe.up.pt/~aaguiar/as/gof/hires/pat5g.htm#samplecode
robi-y

Yanıtlar:


106

Gözlemci modeli: Nesneler arasında bire çok bağımlılığı tanımlar, böylece bir nesnenin durumu değiştiğinde, tüm bağımlıları otomatik olarak bilgilendirilir ve güncellenir.

Arabulucu modeli: Bir dizi nesnenin nasıl etkileşimde bulunduğunu özetleyen bir nesne tanımlayın. Mediator, nesnelerin birbirlerine açıkça atıfta bulunmasını önleyerek gevşek eşleşmeyi destekler ve etkileşimlerini bağımsız olarak değiştirmenize olanak tanır.

Kaynak: dofactory

Misal:

Gözlemci örüntüsü: Sınıf A, kendisine kayıtlı sıfır veya daha fazla O tipi gözlemciye sahip olabilir. A'daki bir şey değiştiğinde tüm gözlemcileri bilgilendirir.

Arabulucu örüntü: X sınıfının bazı örneklerine sahipsiniz (veya belki birkaç farklı tür: X, Y ve Z) ve birbirleriyle iletişim kurmak istiyorlar (ancak her birinin her birine açık referanslar olmasını istemiyorsunuz. diğer), böylece bir aracı sınıf M oluşturursunuz. Her X örneğinin, diğer X (veya X, Y ve Z) örnekleriyle iletişim kurabileceği paylaşılan bir M örneğine bir referansı vardır.


gözlemcinin açıklama yerine gözlemci desen daha komut desen yakın gibi görünüyor
Aun

42

Gözlemci ve Arabulucu, Tasarım Kalıpları, Yeniden Kullanılabilir Nesne Yönelimli Yazılımın Unsurları terimlerini bulan orijinal kitapta , Arabulucu örüntüsünün gözlemci kalıbı kullanılarak gerçekleştirilebileceğini söylüyor. Bununla birlikte, Meslektaşların (yaklaşık olarak Gözlemci modelinin Öznelerine eşdeğer olan) bir Arabulucu sınıfına veya bir Arabulucu arayüzüne bir referansı olmasıyla da uygulanabilir.

Gözlemci modelini kullanmak isteyeceğiniz birçok durum vardır, bunların anahtarı, nesnenin diğer hangi nesnelerin durumunu gözlemlediğini bilmemesidir.

Arabulucu biraz daha spesifiktir, sınıfların doğrudan değil arabulucu aracılığıyla iletişim kurmasını önler. Bu, iletişimin yalnızca iletişimi idare eden bir sınıfa aktarılmasına izin vererek Tek Sorumluluk ilkesine yardımcı olur.

Klasik bir Arabulucu örneği, saf yaklaşımın "Foo paneli devre dışı bırakılırsa ve Bar panelinde" Lütfen tarih girin "yazan bir etikete sahipse ve ardından sunucuyu aramayın, bir düğme tıklama olayında koda yol açabilir. Aksi takdirde devam edin ", burada Arabulucu modeliyle" Ben sadece bir düğmüyüm ve Foo paneli ve Çubuk panelindeki etiket hakkında hiçbir dünyevi işim yok, bu yüzden arabulucuma sunucuyu arayıp aramayacağını soracağım şu anda sorun yok. "

Veya, Arabulucu, Gözlemci kalıbı kullanılarak uygulanırsa, düğme "Hey, gözlemciler (arabulucu da dahil), durumum değişti (biri beni tıkladı). Önemsiyorsanız bu konuda bir şeyler yapın" diyecektir. Benim örneğimde, bu muhtemelen arabulucuya doğrudan atıfta bulunmaktan daha az mantıklıdır, ancak çoğu durumda Arabulucu uygulamak için Gözlemci modelini kullanmak mantıklı olacaktır ve Gözlemci ile Arabulucu arasındaki fark, kodun kendisindeki bir farktan çok bir amaç olacaktır.


Bu "Tek Sorumluluk ilkesi" kelimesini arıyordum.
stdout

37

Gözlemci

1. Olmadan

  • Client1 : Hey Konu , ne zaman değişiyorsun?

  • Client2 : Konuyu ne zaman değiştirdiniz ? Fark etmedim!

  • Client3 : Konunun değiştiğini biliyorum .

2. İle

  • Müşteriler sessiz.
  • Bir süre sonra ...
  • Konu : Değerli müşterilerim , değiştim!

Arabulucu

1. Olmadan

  • İstemci1 : Hey Taxi1 , bana bazı yerlerde alır.
  • İstemci2 : Hey Taxi1 , bana bazı yerlerde alır.
  • İstemci1 : Hey Taxi2 , bana bazı yerlerde alır.
  • İstemci2 : Hey Taxi2 , bana bazı yerlerde alır.

2. İle

  • İstemci1 : Hey TaxiCenter , bana bir atın taksi .
  • İstemci2 : Hey TaxiCenter , bana bir atın taksi .

2
Arabulucu örneğiniz arabulucu modeli değil fabrika kalıbıdır
Mohammad Karimi

3
@Pmpr Arabulucu tasarım kalıbıdır. (TaxiCenter o sıranızı diyor kadar muhtemelen her taksi bekler) TaxiCenter bazı yollarla temin taxies yapar, taxies oluşturmayacaktır
Siva R

14

Bu modeller farklı durumlarda kullanılır:

Arabulucu örüntü, bir bağımlılığı olan iki alt sisteminiz olduğunda ve bunlardan birinin değişme zamanı geldiğinde kullanılır ve diğerine bağlı olan sistemi değiştirmek istemeyebileceğiniz için, bir arabulucu tanıtmak isteyebilirsiniz. aralarındaki bağımlılığı ayırın. Bu şekilde, alt sistemlerden biri değiştiğinde, yapmanız gereken tek şey arabulucuyu güncellemektir.

Gözlemci örüntüsü, bir sınıf diğer sınıfların kendilerini kaydetmelerine ve olaylar hakkında bildirim almalarına izin vermek istediğinde kullanılır, örn.

Bu modellerin her ikisi de daha az bağlantıya izin verir, ancak oldukça farklıdır.


10

Bir örnek verelim: iki uygulama oluşturmak istediğinizi düşünün:

  1. Sohbet uygulaması.
  2. Acil ambulans operatörü uygulaması.

arabulucu

Sohbet uygulamasını oluştururken mediatortasarım modelini seçeceksiniz.

  • Kişiler herhangi bir zamanda sohbete katılabilir veya sohbete ayrılabilir, bu nedenle sohbet eden iki kişi arasında doğrudan referans tutmak mantıklı değildir.
  • Hala iki kişi arasındaki iletişimi kolaylaştırmalı ve sohbet etmelerine izin vermeliyiz.

Neden tercih edeceğiz mediator? sadece tanımına bir göz atın:

Arabulucu model ile, nesneler arasındaki iletişim bir aracı nesnesi içinde kapsüllenir. Nesneler artık birbirleriyle doğrudan iletişim kurmuyor, bunun yerine arabulucu aracılığıyla iletişim kuruyor. Bu, iletişim kuran nesneler arasındaki bağımlılıkları azaltır ve böylece eşleşmeyi azaltır.

Sihir nasıl çalışır? Öncelikle sohbet aracısını oluşturacağız ve kişilerin nesnelerini ona kaydettireceğiz, böylece her bir kişiyle iki yönlü bağlantı kuracak (kişi sohbet aracısını kullanarak mesaj gönderebilir, çünkü ona erişebilir ve sohbet aracısı erişebilir. kişi nesnesinin alınan yöntemi, ona da erişimi vardır)

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

gözlemci

911 çağrı uygulamasını oluştururken observertasarım modelini seçeceksiniz.

  • Her ambulans observernesnesi acil bir durum olduğunda haberdar edilmek ister, böylece adresi sürdürebilir ve yardım edebilir.
  • Acil durum operatörü observable, ambulansın her birine atıfta bulunur observersve yardıma ihtiyaç duyulduğunda (veya olay oluşturduğunda) onları bilgilendirir.

Neden tercih edeceğiz observer? sadece tanımına bir göz atın:

Özne adı verilen bir nesne, bağımlılarının bir listesini tutar, gözlemci olarak adlandırılır ve genellikle yöntemlerinden birini çağırarak herhangi bir durum değişikliğinden onları otomatik olarak bilgilendirir.

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

Farklılıklar:

  1. Sohbet mediator, operatörün observabletek yönlü iletişime sahip olduğu (ambulansa observersürmesini ve bitirmesini söyler ) kişiler nesneleri arasında iki yönlü iletişime sahiptir (gönderme ve alma ).
  2. Sohbet mediator, kişilerin nesnelerinin aralarında etkileşime girmesini sağlayabilir (doğrudan bir iletişim olmasa bile), ambulanslar observersyalnızca operatör observableolaylarına kaydolur .
  3. Her kişi nesnesinin sohbete bir referansı vardır mediatorve ayrıca sohbet mediator, kişilerin her birine atıfta bulunur. Ambulansın observeroperatöre atıfta bulunmadığı durumlarda observable, yalnızca operatör observableher ambulansı referans alır observer.

4
Son kısım yardımcı olur. Arabulucu ve Gözlemci aynı amacı gerçekleştirir, ancak arabulucu iki yönlü iletişimi sağlarken, gözlemci yalnızca tek yönlü çalışır.
kiwicomb123

Kesinlikle, yardımcı olmasına sevindim
Shahar Shokrani

Başlığı okuduğumda tam tersi oldu aslında Ambulans çağrı merkezi bir arabulucu - bir çağrı alan ve ardından bir ambulans, polis ve itfaiye gönderen Ve radyo istasyonundaki her ambulans evet bir gözlemci - radyoda olay beklerler onlara dokunan sohbette: sunucu bir arabulucudur, her müşteri - gözlemci Size göre doğru geliyor mu?
Maks

Hey @Maks, ambulansın otomatik olduğunu düşün, operatörleriyle telsizle iletişime geçmiyorlar, sadece konumu al ve sür.
Shahar Shokrani

Hey @Maks, yorumunuz cevabıma dayalı bir makale yazmak için bana motivasyon verdi: shokrano.medium.com/mediator-vs-observer-19e3b21ef31c teşekkürler!
Shahar Shokrani

7

Her ikisi de durum değişikliklerini organize bir şekilde anlatmak için kullanılsa da, yapısal ve anlamsal olarak biraz farklıdırlar.

Gözlemci, belirli bir nesnenin durum değişikliğini nesnenin kendisinden yayınlamak için kullanılır. Böylece değişim, aynı zamanda sinyal vermekten de sorumlu olan merkezi nesnede gerçekleşir. Ancak, Arabulucu'da durum değişikliği herhangi bir nesnede olabilir, ancak bir arabulucu tarafından yayınlanır. Yani akışta bir fark var. Ancak bunun kod davranışımızı etkilediğini sanmıyorum. Aynı davranışı elde etmek için birini veya diğerini kullanabiliriz. Öte yandan, bu farkın kodun kavramsal olarak anlaşılması üzerinde bazı etkileri olabilir.

Bakın, kalıpları kullanmanın birincil amacı, geliştiriciler arasında ortak bir dil oluşturmaktır. Bu nedenle, bir arabulucu gördüğümde, iletişim gürültüsünü azaltmak (veya SRP'yi desteklemek için) için tek bir aracı / merkez üzerinden iletişim kurmaya çalışan birden çok unsuru kişisel olarak anlıyorum ve her bir nesne bir durum değişikliğini bildirme yeteneği açısından eşit derecede önemlidir. Örneğin, bir havalimanına yaklaşan birden fazla uçağı düşünün. Her biri birbiriyle iletişim kurmak yerine pilon (arabulucu) üzerinden iletişim kurmalıdır. (İniş sırasında birbirleriyle iletişim kuran 1000 uçağın düşünün - bu bir karmaşa olur)

Bununla birlikte, bir gözlemci gördüğümde, bu, umursayabileceğim ve belirli durum değişikliklerini dinlemek için kaydolmam / abone olmam gereken bazı durum değişiklikleri olduğu anlamına gelir. Durum değişikliklerini bildirmekten sorumlu merkezi bir nesne var. Örneğin, A'dan B'ye giderken belirli bir havalimanını önemsiyorsam, boş bir pist veya buna benzer bir şey varmış gibi yayınlanan bazı olayları yakalamak için o havalimanına kayıt olabilirim.

Umarım açıktır.


5

@cdc niyetteki farkı mükemmel bir şekilde açıkladı.

Üstüne biraz daha bilgi ekleyeceğim.

Gözlemci : Bir nesnedeki bir olayın farklı nesne kümelerine (farklı sınıfların örnekleri) bildirimini etkinleştirir

Arabulucu : Belirli bir sınıftan oluşturulan nesneler kümesi arasındaki iletişimi merkezileştirin.

Dofactory'den Arabulucu modelinin yapısı :

görüntü açıklamasını buraya girin

Arabulucu : Meslektaşlar arasındaki iletişim için bir arayüz tanımlar.

Meslektaş : Meslektaşlar arasında iletilecek olayları tanımlayan soyut bir sınıftır

ConcreteMediator : Meslektaş nesnelerini koordine ederek işbirliği davranışını uygular ve meslektaşlarını korur

ConcreteColleague : Arabulucu aracılığıyla alınan ve diğer İş Arkadaşı tarafından oluşturulan bildirim işlemlerini uygular.

Gerçek bir dünya örneği:

Mesh topolojisinde bir bilgisayar ağı sürdürüyorsunuz . Yeni bir bilgisayar eklenirse veya mevcut bilgisayar kaldırılırsa, o ağdaki diğer tüm bilgisayarlar bu iki olay hakkında bilgi sahibi olmalıdır.

Arabulucu modelinin buna nasıl uyduğunu görelim.

Kod pasajı:

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

çıktı:

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

Açıklama:

  1. Eagle , ilk olarak kayıt olayı ile ağa eklenir. Eagle ilk olduğu için diğer meslektaşlarına bildirim yok.
  2. Ne zaman Devekuşu ağına ilave edilir, Kartal bildirilir: çıkışının Satır 1 şimdi oluşturulur.
  3. Ne zaman Penguen ağına ilave edilir, hem Kartal ve Devekuşu bildirmiştir: Hat 2 ve çıkış Hat 3 şimdi oluşturulur.
  4. Ne zaman Kartal kaydını olay üzerinden ağ sol, hem Devekuşu ve Penguen haberdar edildi. Çıktının 4. Satırı ve 5. Satırı şimdi işleniyor.

2

Nasıl Bu açıklama hakkında Teknik olarak hem Gözlemci hem de Aracı aynıdır ve bileşen iletişimi için ayrıştırılmış bir yol sağlamak için kullanılır, ancak kullanım farklıdır.

Abone olunan bileşenlere durum değişiklikleri hakkında obeserver bildirimde bulunurken (örneğin, yeni db kaydının oluşturulması), kayıtlı bileşenlere iş mantığı akışıyla ilgili bir şeyler yapmak için komutlar (şifre sıfırlama için kullanıcıya e-posta gönderme).mediator

Gözlemci

  • Bildirim tüketicileri bildirim almak için abone olmaktan sorumludur.
  • Bildirim işleme, iş akışının bir parçası değil

Arabulucu

  • "Yayıncı" ve "tüketiciler" arasında bağlantı kurmak için açık kayıt gerekir
  • Bildirim işleme, belirli iş akışının bir parçasıdır
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.