中介者模式

概述

中介者模式(Mediator Pattern)是用來降低多個對象和類之間的通訊複雜性。這種模式提供了一個中介類,該類通常處理不同類之間的通訊,並支援松耦合,使程式碼易於維護。中介者模式屬於行為型模式。

在現實生活中,常常會出現好多對象之間存在複雜的交互關係,這種交互關係常常是「網狀結構」,它要求每個對象都必須知道它需要交互的對象。例如,每個人必須記住他(她)所有朋友的電話;而且,朋友中如果有人的電話修改了,他(她)必須告訴其他所有的朋友修改,這叫作「牽一髮而動全身」,非常複雜。

如果把這種「網狀結構」改為「星形結構」的話,將大大降低它們之間的「耦合性」,這時只要找一個「中介者」就可以了。如前面所說的「每個人必須記住所有朋友電話」的問題,只要在網上建立一個每個朋友都可以訪問的「通訊錄」就解決了。這樣的例子還有很多,例如,你剛剛參力口工作想租房,可以找「房屋中介」;或者,自己剛剛到一個陌生城市找工作,可以找「人才交流中心」幫忙。

在軟體的開發過程中,這樣的例子也很多,例如,在 MVC 框架中,控制器(C)就是模型(M)和視圖(V)的中介者;還有大家常用的 QQ 聊天程式的「中介者」是 QQ 伺服器。所有這些,都可以採用「中介者模式」來實現,它將大大降低對象之間的耦合性,提高系統的靈活性。

模式的定義與特點

中介者(Mediator)模式的定義:定義一個中介對象來封裝一系列對象之間的交互,使原有對象之間的耦合鬆散,且可以獨立地改變它們之間的交互。中介者模式又叫調停模式,它是迪米特法則的典型應用。

中介者模式是一種對象行為型模式,其主要優點如下。

  1. 降低了對象之間的耦合性,使得對象易於獨立地被複用。

  2. 將對象間的一對多關聯轉變為一對一的關聯,提高系統的靈活性,使得系統易於維護和擴展。

其主要缺點是:當同事類太多時,中介者的職責將很大,它會變得複雜而龐大,以至於系統難以維護。

模式的結構與實現

中介者模式實現的關鍵是找出「中介者」,下面對它的結構和實現進行分析。

1. 模式的結構

中介者模式包含以下主要角色。

  1. 抽象中介者(Mediator)角色:它是中介者的介面,提供了同事對象註冊與轉發同事對象資訊的抽象方法。

  2. 具體中介者(ConcreteMediator)角色:實現中介者介面,定義一個 List 來管理同事對象,協調各個同事角色之間的交互關係,因此它依賴於同事角色。

  3. 抽象同事類(Colleague)角色:定義同事類的介面,保存中介者對象,提供同事對象交互的抽象方法,實現所有相互影響的同事類的公共功能。

  4. 具體同事類(Concrete Colleague)角色:是抽象同事類的實現者,當需要與其他同事對象交互時,由中介者對象負責後續的交互。


中介者模式的結構圖如圖 1 所示。

中介者模式的结构图
 

2. 模式的實現

中介者模式的實現程式碼如下:

package mediator;
import java.util.*;
public class MediatorPattern {
    public static void main(String[] args) {
        Mediator md=new ConcreteMediator();
        Colleague c1,c2;
        c1=new ConcreteColleague1();
        c2=new ConcreteColleague2();
        md.register(c1);
        md.register(c2);
        c1.send();
        System.out.println("-------------");
        c2.send();
    }
}
//抽象中介者
abstract class Mediator {
    public abstract void register(Colleague colleague);
    public abstract void relay(Colleague cl); //轉發
}
//具體中介者
class ConcreteMediator extends Mediator {
    private List<Colleague> colleagues=new ArrayList<Colleague>();
    public void register(Colleague colleague) {
        if(!colleagues.contains(colleague)) {
            colleagues.add(colleague);
            colleague.setMedium(this);
        }
    }
    public void relay(Colleague cl) {
        for(Colleague ob:colleagues) {
            if(!ob.equals(cl)) {
                ((Colleague)ob).receive();
            }   
        }
    }
}
//抽象同事類
abstract class Colleague {
    protected Mediator mediator;
    public void setMedium(Mediator mediator) {
        this.mediator=mediator;
    }   
    public abstract void receive();   
    public abstract void send();
}
//具體同事類
class ConcreteColleague1 extends Colleague {
    public void receive(){
        System.out.println("具體同事類1收到請求。");
    }   
    public void send() {
        System.out.println("具體同事類1發出請求。");
        mediator.relay(this); //請中介者轉發
    }
}
//具體同事類
class ConcreteColleague2 extends Colleague {
    public void receive(){
        System.out.println("具體同事類2收到請求。");
    }   
    public void send(){
        System.out.println("具體同事類2發出請求。");
        mediator.relay(this); //請中介者轉發
    }
}

 程式的運行結果如下:

具體同事類1發出請求。
具體同事類2收到請求。
-------------
具體同事類2發出請求。
具體同事類1收到請求。

模式的應用場景

前面分析了中介者模式的結構與特點,下面分析其以下應用場景。

  • 當對象之間存在複雜的網狀結構關係而導致依賴關係混亂且難以復用時。

  • 當想創建一個運行於多個類之間的對象,又不想生成新的子類時。

模式的擴展

在實際開發中,通常採用以下兩種方法來簡化中介者模式,使開發變得更簡單。

  1. 不定義中介者介面,把具體中介者對象實現成為單例。

  2. 同事對象不持有中介者,而是在需要的時f矣直接獲取中介者對象並調用。

下圖是簡化中介者模式的結構圖。

简化中介者模式的结构图

程式程式碼如下:
package mediator;
import java.util.*;
public class SimpleMediatorPattern {
    public static void main(String[] args) {
        SimpleColleague c1,c2;
        c1=new SimpleConcreteColleague1();
        c2=new SimpleConcreteColleague2();
        c1.send();
        System.out.println("-----------------");
        c2.send();
    }
}
//簡單單例中介者 class SimpleMediator {
   // 確保只初始化一次
private static SimpleMediator smd=new SimpleMediator(); private List<SimpleColleague> colleagues=new ArrayList<SimpleColleague>(); private SimpleMediator(){}
  // 做成單例
public static SimpleMediator getMedium(){
    
return(smd);
  }
public void register(SimpleColleague colleague) { if(!colleagues.contains(colleague)){ colleagues.add(colleague); } }
public void relay(SimpleColleague scl) { for(SimpleColleague ob:colleagues) { if(!ob.equals(scl)) { ((SimpleColleague)ob).receive(); } } } }
//抽象同事類 interface SimpleColleague { void receive(); void send(); }
//具體同事類 class SimpleConcreteColleague1 implements SimpleColleague { SimpleConcreteColleague1(){ SimpleMediator smd=SimpleMediator.getMedium(); smd.register(this); } public void receive() {
    System.out.println(
"具體同事類1:收到請求。");
  }
public void send() { SimpleMediator smd=SimpleMediator.getMedium(); System.out.println("具體同事類1:發出請求..."); smd.relay(this); //請中介者轉發 } }
//具體同事類 class SimpleConcreteColleague2 implements SimpleColleague { SimpleConcreteColleague2(){ SimpleMediator smd=SimpleMediator.getMedium(); smd.register(this); }
public void receive() {
    System.out.println(
"具體同事類2:收到請求。");
  }
public void send() { SimpleMediator smd=SimpleMediator.getMedium(); System.out.println("具體同事類2:發出請求..."); smd.relay(this); //請中介者轉發 } }

 程式運行結果如下:

具體同事類1:發出請求...
具體同事類2:收到請求。
-----------------
具體同事類2:發出請求...
具體同事類1:收到請求。

 

觀察者模式和中介者模式的異同

1. 基本定義區別

  • 觀察者模式:屬於行為型模式,指多個對象間存在一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。這種模式有時又稱作發布-訂閱模式、模型-視圖模式。中介者模式:

  • 中介者模式:屬於行為型模式;定義一個中介對象來封裝一系列對象之間的交互,使原有對象之間的耦合鬆散,且可以獨立地改變它們之間的交互。中介者模式又叫調停模式,它是迪米特法則的典型應用。

相同點:

  • 都屬於行為型模式

  • 都為了處理一對多的關係

2. URML圖區別:

觀察者模式:

中介者模式:

相同點:
  • 處理業務邏輯的對象都被抽象化(ConcreteColleague和ConcreteObserver都符合單一職責)

  • 中介者和觀察者都有統一管理的list集合。

  • 都有循環通知的方法

3. 使用場景

  • 觀察者模式:只能從從一的一方循環的通知,屬於單向。(好比上課,只能老實授課給班上所有的學生,反過來不行)

  • 中介者模式:可以從任一方循環通知,屬於雙向。(好比分享會,每個人都可以分享自己的事情給別人)


參考文章