热门问题
时间线
聊天
视角

中介者模式

来自维基百科,自由的百科全书

Remove ads

軟件工程領域,中介者模式(英語:mediator pattern),定義了一個中介者對象,該對象封裝了系統中對象間的交互方式。 由於它可以在運行時改變程序的行為,這種模式是一種行為型模式

Thumb
中介者設計模式

通常程序由大量的組成,這些類中包含程序的邏輯和運算。 然而,當開發者將更多的類加入到程序中之後,類間交互關係可能變得更為複雜,這會使得代碼變得更加難以閱讀和維護,尤其是在重構的時候。 此外,程序將會變得難以修改,因為對其所做的任何修改都有可能影響到其它幾個類中的代碼。

在中介者模式中,「同事」對象間的通信過程被封裝在一個「中介者」(調解人)對象之中。 對象之間不再直接交互,而是通過調解人進行交互。 這麼做可以減少可交互對象間的依賴,從而降低耦合

概述

中介者模式[1]是23個周知模式( 即GoF《設計模式》)中的一個,GoF設計模式旨在提供重複出現的設計問題的解決方案,以編寫靈活和可復用的面向對象軟件。也就是說,使對象更加易於實現、修改、測試和復用。

中介者設計模式可以解決什麼問題? [2]

  • 避免一組相互交互的對象之間出現緊耦合。
  • 能夠獨立地改變一組對象之間的交互關係而不影響其他對象。

使用直接逐個訪問並更新彼此的方式進行對象間的交互靈活性低,因為這種方式使對象彼此間緊密耦合,導致不可能單獨修改類間交互關係本身,而不影響關係中進行交互的類。並且這種方式會令對象變得無法復用,並且難以測試。

由於「緊耦合」的對象過多了解其他對象的內部細節,這種對象難以實現、修改、測試以及復用。

中介者模式如何解決上述問題?

  • 定義一個獨立的中介者(調解員)的對象,封裝一組對象之間的交互關係。
  • 對象將自己的交互委託給中介者執行,避免直接與其他對象進行交互。

對象利用中介者對象與其他對象進行間接交互,中介者對象負責控制和協調交互關係,這麼做可使得對象間「鬆耦合」。這些對象只訪問中介者,不了解其他對象的細節。另見UML類圖和時序圖如下。

Remove ads

定義

中介者模式是為了「定義一個封裝了對象間交互關係的對象」。這種方式避免了顯式調用其他類,促進了類間的鬆耦合,並且使得類間交互關係本身可以單獨修改[3]。客戶類可以使用中介者向其他客戶類發送信息,並且通過中介者引發的事件收到信息。

結構

Thumb
一個中介者模式典型實現的UML類圖和時序圖。[4]

在以上UML類圖中,類Colleague1Colleague2不引用和更新彼此。相反,它們引用一個通用的Mediator接口以實現類間交互的控制和協調(通過mediate()),這使得它們獨立於類間交互的具體細節。類Mediator1實現了類Colleague1Colleague2之間的交互細節。

上述UML時序圖顯示了這些類之間在運行時的交互過程:在這個例子中,一個Mediator1對象中介,即控制和協調了Colleague1Colleague2的對象之間的交互。

如果Colleague1的對象需要與Colleague2的對象進行交互,例如更新或者同步狀態,Colleague1調用Mediator1對象的mediate(this)方法,以此得到對Colleague1對象(自己)的改動信息,並且在Colleague2的對象上執行action2()方法。

此後,Colleague2對象調用Mediator1對象的mediate(this)方法,得到對Colleague2(自己)的修改的數據,並且對Colleague1對象調用action1() 方法。

參與者

  • Mediator:定義 Colleague對象之間的交互接口。
  • ConcreteMediator,比如Mediator1:實現了Mediator接口,並且協調Colleague對象之間的交互,知道所有的Colleagues對象以及其交互目的。
  • Colleague:定義了通過Mediator與其他Colleague對象交互的接口。
  • ConcreteColleague,比如Colleague1Colleague2:實現了Colleague接口,並且通過它的Mediator與其他Colleague交互。

範例

Java

在以下示例中,一個中介者對象控制了三個互相交互的按鈕的狀態,為此它有設置狀態的三個方法:book(), view()search()。 當相應的按鈕被激活時,對應的方法通過execute()方法被調用。

於是這裏在交互中每個交互的參與者(本例中即按鈕)將自己的行為提交給中介者並且由中介者將這些行為轉給對應的參與者。

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

//Colleague interface
interface Command {
    void execute();
}

//Abstract Mediator
interface Mediator {
    void book();
    void view();
    void search();
    void registerView(BtnView v);
    void registerSearch(BtnSearch s);
    void registerBook(BtnBook b);
    void registerDisplay(LblDisplay d);
}

//Concrete mediator
class ParticipantMediator implements Mediator {
    BtnView btnView;
    BtnSearch btnSearch;
    BtnBook btnBook;
    LblDisplay show;

    //....
    public void registerView(BtnView v) {
        btnView = v;
    }

    public void registerSearch(BtnSearch s) {
        btnSearch = s;
    }

    public void registerBook(BtnBook b) {
        btnBook = b;
    }

    public void registerDisplay(LblDisplay d) {
        show = d;
    }

    public void book() {
        btnBook.setEnabled(false);
        btnView.setEnabled(true);
        btnSearch.setEnabled(true);
        show.setText("booking...");
    }

    public void view() {
        btnView.setEnabled(false);
        btnSearch.setEnabled(true);
        btnBook.setEnabled(true);
        show.setText("viewing...");
    }

    public void search() {
        btnSearch.setEnabled(false);
        btnView.setEnabled(true);
        btnBook.setEnabled(true);
        show.setText("searching...");
    }
}

//A concrete colleague
class BtnView extends JButton implements Command {
    Mediator med;

    BtnView(ActionListener al, Mediator m) {
        super("View");
        addActionListener(al);
        med = m;
        med.registerView(this);
    }

    public void execute() {
        med.view();
    }
}

//A concrete colleague
class BtnSearch extends JButton implements Command {
    Mediator med;

    BtnSearch(ActionListener al, Mediator m) {
        super("Search");
        addActionListener(al);
        med = m;
        med.registerSearch(this);
    }

    public void execute() {
        med.search();
    }
}

//A concrete colleague
class BtnBook extends JButton implements Command {
    Mediator med;

    BtnBook(ActionListener al, Mediator m) {
        super("Book");
        addActionListener(al);
        med = m;
        med.registerBook(this);
    }

    public void execute() {
        med.book();
    }
}

class LblDisplay extends JLabel {
    Mediator med;

    LblDisplay(Mediator m) {
        super("Just start...");
        med = m;
        med.registerDisplay(this);
        setFont(new Font("Arial", Font.BOLD, 24));
    }
}

class MediatorDemo extends JFrame implements ActionListener {
    Mediator med = new ParticipantMediator();

    MediatorDemo() {
        JPanel p = new JPanel();
        p.add(new BtnView(this, med));
        p.add(new BtnBook(this, med));
        p.add(new BtnSearch(this, med));
        getContentPane().add(new LblDisplay(med), "North");
        getContentPane().add(p, "South");
        setSize(400, 200);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent ae) {
        Command comd = (Command) ae.getSource();
        comd.execute();
    }

    public static void main(String[] args) {
        new MediatorDemo();
    }
}
Remove ads

C#

中介者模式確保了構件之間的鬆耦合,使得它們不直接調用彼此,而是通過中介者調用彼此。 在下面的例子中,調解人註冊了所有的構件,然後調用了它們的SetState方法。

public interface IComponent {
    void SetState(object state);
}

public class Component1 : IComponent {
    public void SetState(object state) {
        throw new NotImplementedException();
    }
}

public class Component2 : IComponent {
    public void SetState(object state) {
        throw new NotImplementedException();
    }
}

// Mediates the common tasks
public class Mediator {
    public IComponent Component1 { get; set; }
    public IComponent Component2 { get; set; }

    public void ChangeState(object state) {
        this.Component1.SetState(state);
        this.Component2.SetState(state);
    }
}

一個聊天室,或者一個需要客戶彼此間每次發送消息之後執行動作的系統(對聊天室來說就是每個人之間發送消息)可以使用中介者模式。但實際上對聊天室使用中介者模式只在包含遠程功能時有用。 原生的套接字不允許委託回呼函式(即通過中介者類訂閱的 MessageReceived 事件)。

public delegate void MessageReceivedEventHandler(string message, string from);

public class Mediator {
    public event MessageReceivedEventHandler MessageReceived;

    public void Send(string message, string from) {
        if (MessageReceived != null) {
            Console.WriteLine("Sending '{0}' from {1}", message, from);
            MessageReceived(message, from);
        }
    }
}

public class Person {
    private Mediator _mediator;

    public string Name { get; set; }

    public Person(Mediator mediator, string name) {
        Name = name;
        _mediator = mediator;
        _mediator.MessageReceived += new MessageReceivedEventHandler(Receive);
    }

    private void Receive(string message, string from) {
        if (from != Name)
            Console.WriteLine("{0} received '{1}' from {2}", Name, message, from);
    }

    public void Send(string message) {
        _mediator.Send(message, Name);
    }
}
Remove ads

Python

下面是Python的例子:

from abc import ABC, abstractmethod

class Colleague(ABC):
    @abstractmethod
    def get_state(self): pass
    @abstractmethod
    def set_state(self): pass
    @abstractmethod
    def action(self): pass
    @abstractmethod
    def mediate_with(self, other): pass

class ColleagueA(Colleague):
    def __init__(self, mediator):
        self.state = []
        self.kwstate = {}
        self.mediator = mediator
        mediator.register_colleague(self)
    def get_state(self):
        return self.state, self.kwstate
    def set_state(self, *args, **kwargs):
        self.state = args
        self.kwstate = kwargs
    def action(self, other, *args, **kwargs):
        print(self, "Got", args, kwargs, "From", other)
    def mediate_with(self, other):
        self.mediator.mediate(self, other)

class Mediator():
    def __init__(self):
        self.__colleagues = []
    def register_colleague(self, coll):
        self.__colleagues.append(coll)
    def unregister_colleague(self, coll):
        self.__colleagues.remove(coll)
    def mediate(self, src, dest):
        assert src in self.__colleagues
        assert dest in self.__colleagues
        temp0, temp1 = src.get_state()
        dest.action(src, *temp0, **temp1)

其執行:

>>> mediator = Mediator()
>>> colleague1 = ColleagueA(mediator)
>>> colleague2 = ColleagueA(mediator)
>>> colleague1.set_state("test", kw="python")
>>> colleague1.mediate_with(colleague2)
<__main__.ColleagueA object at 0x7d60b1bb7ed0> Got ('test',) {'kw': 'python'} From <__main__.ColleagueA object at 0x7d60b1a54980>
Remove ads

另見

參考文獻

外部連結

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads