Mediator Vs Observer Các mẫu thiết kế hướng đối tượng


93

Tôi đã đọc Gang Of Four , để giải quyết một số vấn đề của mình và bắt gặp mô hình Mediator .

Trước đó tôi đã sử dụng Observer trong các dự án của mình để tạo một số ứng dụng GUI. Tôi hơi bối rối vì tôi không tìm thấy sự khác biệt lớn giữa hai loại. Tôi đã duyệt để tìm sự khác biệt nhưng không thể tìm thấy bất kỳ câu trả lời phù hợp nào cho truy vấn của mình.

Ai đó có thể giúp tôi phân biệt giữa hai điều này với một số ví dụ điển hình giúp phân định rõ ràng hai điều này không?


5
Yêu cầu của tôi để chuyển câu hỏi này sang Programmers.StackExchangeđã bị từ chối, nhưng tôi đã thực hiện một bài đăng tương tự ở đó vì tôi quan tâm đến câu trả lời. Bạn có thể thấy một số câu trả lời thú vị. :)
Rachel

Đối với các ví dụ về JavaScript, bạn có thể xem câu trả lời của tôi cho một câu hỏi tương tự .
Alex Pakka

Sách GoF gốc giải quyết vấn đề đó trong phần triển khai điểm # 8, bằng cách đưa ra một ví dụ về một ChangeManagercho Observermẫu sử dụng Mediator. xem; paginas.fe.up.pt/~aaguiar/as/gof/hires/pat5g.htm#samplecode
-y

Câu trả lời:


104

Mẫu Observer: xác định sự phụ thuộc một-nhiều giữa các đối tượng để khi một đối tượng thay đổi trạng thái, tất cả các thành phần phụ thuộc của nó sẽ được thông báo và cập nhật tự động.

Mẫu Mediator: Xác định một đối tượng đóng gói cách một tập hợp các đối tượng tương tác. Mediator thúc đẩy kết hợp lỏng lẻo bằng cách giữ cho các đối tượng không tham chiếu đến nhau một cách rõ ràng và nó cho phép bạn thay đổi tương tác của chúng một cách độc lập.

Nguồn: dofactory

Thí dụ:

Mẫu quan sát viên: Loại A, có thể có không hoặc nhiều quan sát viên loại O đăng ký với nó. Khi một cái gì đó ở A bị thay đổi, nó sẽ thông báo cho tất cả những người quan sát.

Mẫu dàn xếp: Bạn có một số trường hợp của lớp X (hoặc thậm chí có thể là một số loại khác nhau: X, Y & Z) và chúng muốn giao tiếp với nhau (nhưng bạn không muốn mỗi loại có tham chiếu rõ ràng đến từng khác), do đó bạn tạo một lớp trung gian M. Mỗi bản sao của X có một tham chiếu đến một bản sao dùng chung của M, qua đó nó có thể giao tiếp với các bản sao khác của X (hoặc X, Y và Z).


lời giải thích của người quan sát dường như gần với mô hình lệnh hơn là mô hình người quan sát
Aun

40

Trong cuốn sách gốc đã đặt ra các thuật ngữ Người quan sát và Người dàn xếp, Mẫu thiết kế, Phần tử của phần mềm hướng đối tượng có thể tái sử dụng , nó nói rằng mẫu Người dàn xếp có thể được triển khai bằng cách sử dụng mẫu người quan sát. Tuy nhiên, nó cũng có thể được thực hiện bằng cách để Đồng nghiệp (gần tương đương với Đối tượng của mẫu Người quan sát) có tham chiếu đến lớp Người hòa giải hoặc giao diện Người hòa giải.

Có nhiều trường hợp khi bạn muốn sử dụng mẫu người quan sát, điều quan trọng là một đối tượng không nên biết trạng thái của các đối tượng khác đang quan sát.

Mediator cụ thể hơn một chút, nó tránh để các lớp giao tiếp trực tiếp mà thay vào đó là thông qua một trung gian. Điều này giúp ích cho nguyên tắc Trách nhiệm duy nhất bằng cách cho phép truyền tải thông tin xuống một lớp chỉ xử lý giao tiếp.

Ví dụ về Mediator cổ điển là trong GUI, trong đó cách tiếp cận ngây thơ có thể dẫn đến mã trên một sự kiện nhấp vào nút nói rằng "nếu bảng điều khiển Foo bị tắt và bảng điều khiển Thanh có nhãn" Vui lòng nhập ngày "thì không gọi máy chủ, nếu không, hãy tiếp tục ", trong đó với mẫu Người hòa giải, nó có thể nói" Tôi chỉ là một nút bấm và không có công việc kinh doanh trần tục nào biết về bảng điều khiển Foo và nhãn trên bảng điều khiển Thanh, vì vậy tôi sẽ chỉ hỏi người hòa giải của mình nếu gọi máy chủ hiện đã ổn. "

Hoặc, nếu Người hòa giải được triển khai bằng cách sử dụng mẫu Người quan sát, nút sẽ nói "Này, những người quan sát (bao gồm cả người hòa giải), trạng thái của tôi đã thay đổi (ai đó đã nhấp vào tôi). Hãy làm gì đó nếu bạn quan tâm". Trong ví dụ của tôi, điều đó có thể ít ý nghĩa hơn khi tham chiếu trực tiếp đến người hòa giải, nhưng trong nhiều trường hợp, việc sử dụng mẫu Người quan sát để triển khai Người hòa giải sẽ có ý nghĩa và sự khác biệt giữa Người quan sát và Người hòa giải sẽ là một mục đích hơn là sự khác biệt trong chính mã.


Tôi đã tìm kiếm từ này "Nguyên tắc trách nhiệm duy nhất".
stdout

37

Người quan sát

1. Không có

  • Client1 : Này Chủ đề , khi nào bạn thay đổi?

  • Client2 : Bạn thay đổi Chủ đề khi nào? Tôi đã không nhận thấy!

  • Khách hàng 3 : Tôi biết rằng Chủ đề đã thay đổi.

2. Với

  • Khách hàng im lặng.
  • Một thời gian sau ...
  • Chủ đề : Khách hàng thân mến , tôi đã thay đổi!

Người hòa giải

1. Không có

  • Client1 : Này Taxi1 , đưa tôi đi đâu.
  • Khách hàng 2 : Này Taxi1 , đưa tôi đi đâu.
  • Khách hàng1 : Này Taxi2 , đưa tôi đi đâu.
  • Client2 : Này Taxi2 , đưa tôi đi đâu.

2. Với

  • Khách hàng1 : Này TaxiCenter , vui lòng đón tôi một chiếc Taxi .
  • Khách hàng 2 : Này TaxiCenter , vui lòng đón tôi một chiếc Taxi .

2
Ví dụ trung gian hòa giải của bạn là nhà máy mô hình, không hòa giải mẫu
Mohammad Karimi

2
@Pmpr Đây là mẫu thiết kế dàn xếp. TaxiCenter sẽ không tạo taxi, nó làm cho taxi có sẵn bằng một số phương tiện (có thể mỗi chiếc taxi đợi cho đến khi TaxiCenter nói rằng đến lượt bạn)
Siva R

14

Các mẫu này được sử dụng trong các trường hợp khác nhau:

Mẫu người hòa giải được sử dụng khi bạn có hai hệ thống phụ với một số phụ thuộc và một trong số chúng sắp phải thay đổi và vì bạn có thể không muốn thay đổi hệ thống phụ thuộc vào hệ thống kia, bạn có thể muốn giới thiệu một người hòa giải sẽ tách rời sự phụ thuộc giữa chúng. Theo cách đó, khi một trong các hệ thống con thay đổi, tất cả những gì bạn phải làm là cập nhật bộ hòa giải.

Mẫu quan sát được sử dụng khi một lớp muốn cho phép các lớp khác tự đăng ký và nhận thông báo về các sự kiện, ví dụ: ButtonListener, v.v.

Cả hai mẫu này đều cho phép ghép nối ít hơn, nhưng hoàn toàn khác nhau.


7

Hãy đi qua một ví dụ: xem xét bạn muốn xây dựng hai ứng dụng:

  1. Ứng dụng trò chuyện.
  2. Ứng dụng điều hành xe cấp cứu khẩn cấp.

người hòa giải

Xây dựng ứng dụng trò chuyện, bạn sẽ chọn mediatormẫu thiết kế.

  • Mọi người có thể tham gia và rời khỏi cuộc trò chuyện vào bất kỳ thời điểm nào, vì vậy không có ý nghĩa gì khi giữ thông tin tham khảo trực tiếp giữa hai người đang trò chuyện.
  • Chúng tôi vẫn cần tạo điều kiện giao tiếp giữa hai người và cho phép họ trò chuyện.

Tại sao chúng tôi sẽ thích mediator? chỉ cần xem qua định nghĩa của nó:

Với mẫu trung gian, giao tiếp giữa các đối tượng được gói gọn trong một đối tượng trung gian. Các đối tượng không còn giao tiếp trực tiếp với nhau mà thay vào đó là giao tiếp thông qua trung gian. Điều này làm giảm sự phụ thuộc giữa các đối tượng giao tiếp, do đó giảm sự ghép nối.

Phép thuật hoạt động như thế nào? Trước tiên, chúng tôi sẽ tạo hòa giải trò chuyện và làm cho các đối tượng cá nhân đăng ký với nó, vì vậy nó sẽ có kết nối hai hướng với mọi người (người đó có thể gửi tin nhắn bằng cách sử dụng hòa giải trò chuyện khiến nó truy cập vào nó và người hòa giải trò chuyện sẽ truy cập phương thức đã nhận của đối tượng person vì anh ta cũng có quyền truy cập vào nó)

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

người quan sát

Xây dựng ứng dụng cuộc gọi 911, bạn sẽ chọn observermẫu thiết kế.

  • Mỗi observerđối tượng cứu thương đều mong muốn được thông báo khi có tình trạng khẩn cấp, để lái xe biết địa chỉ và đưa ra yêu cầu giúp đỡ.
  • Người điều hành cấp cứu observablegiữ thông tin liên quan đến từng người trên xe cứu thương observersvà thông báo cho họ khi cần trợ giúp (hoặc phát sinh sự kiện).

Tại sao chúng tôi sẽ thích observer? chỉ cần xem qua định nghĩa của nó:

Một đối tượng, được gọi là chủ thể, duy trì một danh sách các phần tử phụ thuộc của nó, được gọi là các quan sát viên và tự động thông báo cho chúng về bất kỳ thay đổi trạng thái nào, thường bằng cách gọi một trong các phương thức của chúng.

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

Sự khác biệt:

  1. Trò chuyện mediatorcó hai cách giao tiếp giữa các đối tượng người (gửi và nhận) trong khi người điều hành observablechỉ có một cách giao tiếp (Nó yêu cầu xe cấp cứu observerlái xe và kết thúc).
  2. Trò chuyện mediatorcó thể làm cho các đối tượng người tương tác giữa họ (ngay cả khi đó không phải là giao tiếp trực tiếp), xe cứu thương observerschỉ đăng ký các observablesự kiện của người điều hành .
  3. Mỗi đối tượng người có một tham chiếu đến cuộc trò chuyện mediator, và trò chuyện cũng mediatorgiữ tham chiếu đến mỗi người trong số những người đó. Bánh xe cứu thương observerkhông giữ tham chiếu cho người điều hành observable, chỉ người điều hành observablegiữ tham chiếu đến mọi xe cứu thương observer.

3
Điều cuối cùng giúp ích. Người hòa giải và Người quan sát đều hoàn thành cùng một mục tiêu, tuy nhiên, người hòa giải cho phép giao tiếp hai chiều trong khi người quan sát chỉ hoạt động theo một chiều.
kiwicomb123 ngày

Chính xác, rất vui vì nó đã giúp
Shahar Shokrani

6

Mặc dù cả hai đều được sử dụng để thông báo về các thay đổi trạng thái có tổ chức, nhưng IMO về cấu trúc và ngữ nghĩa của chúng hơi khác nhau.

Observer được sử dụng để phát sóng sự thay đổi trạng thái của một đối tượng cụ thể, từ chính đối tượng đó. Vì vậy, sự thay đổi xảy ra trong đối tượng trung tâm cũng chịu trách nhiệm báo hiệu nó. Tuy nhiên, trong Mediator, sự thay đổi trạng thái có thể xảy ra ở bất kỳ đối tượng nào nhưng nó được phát đi từ một người hòa giải. Vì vậy, có một sự khác biệt trong dòng chảy. Nhưng, tôi không nghĩ rằng điều này ảnh hưởng đến hành vi mã của chúng tôi. Chúng ta có thể sử dụng cái này hoặc cái khác để đạt được cùng một hành vi. Mặt khác, sự khác biệt này có thể có một số ảnh hưởng đến sự hiểu biết khái niệm về mã.

Hãy xem, mục đích chính của việc sử dụng các mẫu là để tạo ra một ngôn ngữ chung giữa các nhà phát triển. Vì vậy, khi tôi nhìn thấy một người hòa giải, cá nhân tôi hiểu nhiều yếu tố đang cố gắng giao tiếp qua một nhà môi giới / trung tâm duy nhất để giảm nhiễu giao tiếp (hoặc để thúc đẩy SRP) và mỗi đối tượng đều quan trọng như nhau về khả năng báo hiệu sự thay đổi trạng thái. Ví dụ, hãy nghĩ về nhiều máy bay đến một sân bay. Mỗi người nên giao tiếp qua trụ (trung gian) hơn là giao tiếp với nhau. (Hãy nghĩ đến 1000 máy bay liên lạc với nhau khi hạ cánh - đó sẽ là một mớ hỗn độn)

Tuy nhiên, khi tôi thấy một người quan sát, điều đó có nghĩa là có một số thay đổi trạng thái mà tôi có thể quan tâm và nên đăng ký / đăng ký để lắng nghe những thay đổi trạng thái cụ thể. Có một đối tượng trung tâm chịu trách nhiệm báo hiệu các thay đổi trạng thái. Ví dụ: nếu tôi quan tâm đến một sân bay cụ thể trên đường từ A đến B, tôi có thể đăng ký đến sân bay đó để đón một số sự kiện được phát sóng như nếu có đường băng trống hoặc đại loại như vậy.

Hy vọng nó rõ ràng.


5

@cdc đã giải thích sự khác biệt về ý định một cách xuất sắc.

Tôi sẽ thêm một số thông tin trên đầu trang đó.

Người quan sát : Cho phép thông báo về một sự kiện trong một đối tượng tới các nhóm đối tượng khác nhau (các phiên bản của các lớp khác nhau)

Mediator : Tập trung giao tiếp giữa các đối tượng, được tạo từ một lớp cụ thể.

Cấu trúc của mẫu Trung gian từ nhà máy :

nhập mô tả hình ảnh ở đây

Người hòa giải : Xác định giao diện để giao tiếp giữa các Đồng nghiệp.

Đồng nghiệp : Là một lớp trừu tượng, xác định các sự kiện được giao tiếp giữa các Đồng nghiệp

ConcreteMediator : Thực hiện hành vi hợp tác bằng cách điều phối các đối tượng Đồng nghiệp và duy trì các đồng nghiệp của nó

ConcreteColleague : Triển khai các hoạt động thông báo nhận được thông qua Mediator , được tạo bởi Đồng nghiệp khác

Một ví dụ trong thế giới thực:

Bạn đang duy trì một mạng máy tính trong cấu trúc liên kết Mesh . Nếu một máy tính mới được thêm vào Hoặc máy tính hiện có bị xóa, tất cả các máy tính khác trong mạng đó sẽ biết về hai sự kiện này.

Hãy xem cách Mediator pattern phù hợp với nó.

Đoạn mã:

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

đầu ra:

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

Giải trình:

  1. Eagle được thêm vào mạng lúc đầu thông qua sự kiện đăng ký. Không có thông báo nào cho bất kỳ đồng nghiệp nào khác vì Eagle là người đầu tiên.
  2. Khi Ostrich được thêm vào mạng, Eagle được thông báo: Dòng 1 của đầu ra được hiển thị ngay bây giờ.
  3. Khi Penguin được thêm vào mạng, cả EagleOstrich đều được thông báo: Dòng 2 và Dòng 3 của đầu ra được hiển thị ngay bây giờ.
  4. Khi Eagle rời khỏi mạng thông qua sự kiện hủy đăng ký, cả OstrichPenguin đều đã được thông báo. Dòng 4 và Dòng 5 của đầu ra được hiển thị ngay bây giờ.

2

Làm thế nào Về giải thích này Về mặt kỹ thuật, cả Observer và Mediator đều giống nhau và được sử dụng để cung cấp cách tách rời cho giao tiếp thành phần, nhưng cách sử dụng khác nhau.

Trong khi obeserver thông báo cho các thành phần đã đăng ký về các thay đổi trạng thái (ví dụ: tạo bản ghi db mới), mediator lệnh cho các thành phần đã đăng ký thực hiện điều gì đó liên quan đến luồng logic nghiệp vụ (gửi email đến người dùng để đặt lại mật khẩu).

Người quan sát

  • Thông báo, người tiêu dùng có trách nhiệm đăng ký để nhận thông báo
  • Xử lý thông báo không phải là một phần của quy trình kinh doanh

Người hòa giải

  • Cần đăng ký rõ ràng để kết nối "nhà xuất bản" và "người tiêu dùng"
  • Xử lý thông báo là một phần của quy trình kinh doanh cụ thể
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.