設計模式之中介者模式

2022-09-15 12:01:14

在我們實際業務中,可能存在多個類之間相互呼叫,形成了一個複雜的網狀結構。這時候就需要有一種模式去「捋順」他們之間的關係,引出一箇中間者讓類之間不再相互呼叫,該模式就是我們今天的主人公——中介者模式。

一、概念理解

我們先看中介者模式的官方概念:用一箇中介者物件來封裝一系列的物件互動,中介者使各物件不需要顯示地相互參照,從而使其鬆散耦合,而且可以獨立地改變它們之間的互動。

大白話解釋就是,引入一個「中介」,用於協調各個物件的關係,各個物件之間不用那麼直白的直接調,物件只需要呼叫中介的方法,中介內部進行邏輯判斷,由中介去呼叫各個物件的方法。

概念基本清楚以後接著看中介者模式包含的角色都有哪些:

中介者角色、各個物件角色是必須的,在面向介面程式設計原則下,中介者和物件應該抽離出來介面,於是在中介者模式的結構中就包括四種角色(各個物件角色稱為同事):

1.中介者(Mediator):中介者是一個介面,該介面定義了用於同事(Colleague)物件之間進行通訊的方法;

2.具體中介者(ConcreteMediator):具體中介者是實現中介者介面的類。具體中介者需要包含所有具體同事(ConcreteColleague)的參照,並通過實現中介者介面中的方法來滿足具體同事之間的通訊要求;

3.同事(Colleague):一個介面,規定了具體同事需要實現的方法;

4.具體同事(ConcreteColleague):實現了同事介面的類。具體同事需要包含具體中介者的參照,一個具體同事需要和其他具體同事互動時,只需將自己的請求通知給它所包含的具體中介者的參照。

如果在一個業務場景中,一個公司有很多同事,同事1 管理的有自己的資料,有時候也會呼叫同事2的資料。

在中介者模式下,同事1和同事2 之間不再相互呼叫,由中介者統一呼叫,同事類中要持有中介者物件,中介者方法中要有判斷屬於哪個角色的方法。

基於四個角色,實現初試的demo。

讀者可以拉取完整程式碼到本地進行學習,實現程式碼均測試通過後上傳到碼雲

二、案例實現

抽象同事類:

抽象同事中要持有中介者的參照

/**
 * 抽象同事類
 * @author tcy
 * @Date 14-09-2022
 */
public abstract class Colleague {

    //抽象中介者參照
    protected Mediator mediator;

    public Colleague(Mediator mediator)
    {
        this.mediator = mediator;
    }
    //資料更新方法
    public abstract void update();
    //資料更改方法
    public abstract void changed();
}

具體同事類1、2:

具體同事類除了有自己的業務邏輯之外,應該還有額外呼叫中介者的方法

/**
 * 具體同事2
 * @author tcy
 * @Date 14-09-2022
 */

public class ConcreteColleague2 extends Colleague {

    public ConcreteColleague2(Mediator mediator)
    {
        super(mediator);
    }

    //自己的方法
    @Override
    public void update()
    {
        System.out.println("更新同事類2");
    }

    //呼叫同事的方法
    @Override
    public void changed()
    {
        System.out.println("同事類2資料更改");
        mediator.operation(this);
    }

}

/**
 * 具體同事1
 * @author tcy
 * @Date 14-09-2022
 */
public class ConcreteColleague1 extends Colleague{

    public ConcreteColleague1(Mediator mediator)
    {
        super(mediator);
    }

    @Override
    public void update()
    {
        System.out.println("更新同事類1");
    }

    @Override
    public void changed()
    {
        System.out.println("同事類1資料更改");
        mediator.operation(this);
    }


}

抽象中介者:

抽象中介者應該是持有所有同事物件,並且應該有一個方法去呼叫別的同事

/**
 * 抽象中介者
 */
public abstract class Mediator {

    protected ArrayList<Colleague> colleagues = new ArrayList<>();

    public void add(Colleague colleague)
    {
        colleagues.add(colleague);
    }

    public abstract void operation(Colleague colleague);

}

具體中介者:

具體中介者實現抽象中介者的方法,根據條件呼叫不同的同事

/**
 * 具體中介者
 * @author tcy
 * @Date 14-09-2022
 */
public class ConcreteMediator extends Mediator {

    @Override
    public void operation(Colleague colleague)
    {
        if(colleague instanceof ConcreteColleague1)
            colleagues.get(1).update();
        else if(colleague instanceof ConcreteColleague2)
            colleagues.get(0).update();
    }

}

三、中介者模式原始碼中的應用

中介者模式的典型應用就是Jdk中的Timer 類。

我們知道Timer 類的主要作用是用於定時任務,定時任務之間會存在通訊問題,如果眾多的定時任務都相互通訊,那對於系統物件間的參照來說就是一災難,引出中介者模式就是理所應當的了。

當有新的任務加入到佇列中,均把該任務當做同事,各個任務之間的通訊都是由Timer 類來完成,Timer 類就相當於中介者的角色。

我們知道,Timer 類實現定時任務的主要方法就是schedule(),schedule()有一堆的過載方法。

我們點開任意的schedule方法。

public void schedule(TimerTask task, Date firstTime, long period) {
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, firstTime.getTime(), -period);
}

均呼叫了sched()私有方法。

我們重點看紅線標記的程式碼塊,將任務放入一個 佇列中,這個佇列和我們例子中的Arrlist是一個作用。

private final TaskQueue queue = new TaskQueue();

判斷以後,呼叫Object的notify()方法,進行執行緒間的通訊。

試想一下,如果沒有這個中介,每個定時任務都手動的呼叫notify()方法,該有多麼痛苦。

四、總結

網上講解設計模式的文章很多,能把中介模式講清楚很簡單,但能說明白何時使用合適的設計模式卻是難上加難。在前三章設計模式的基礎之上,第四章總結看完,希望讀者能對正確使用設計模式有一個清晰的輪廓。

很多網上的部落格都說要職責清晰才可使用中介者模式,如果類的職責是混亂的,那中介者的邏輯寫起來就很難受。還有多個物件間耦合嚴重,類圖之間出現了網狀結構,這時候就可以考慮中介者模式了,如果僅僅是為了使用中介者模式而使用,那就得不償失了。

中介者的優點突出,中介者模式的出現會讓網狀結構,有序的轉化為星狀結構。能有序降低類的複雜度,將多對多的關係轉化為一對多,降低了類之間的耦合。

缺點也很明顯,會增加類的個數,同事類越多,中介者的邏輯也就越複雜。

我已經連續更新了十幾篇設計模式部落格,推薦你一塊學習。

一、設計模式概述

二、設計模式之工廠方法和抽象工廠

三、設計模式之單例和原型

四、設計模式之建造者模式

五、設計模式之代理模式

六、設計模式之介面卡模式

七、設計模式之橋接模式

八、設計模式之組合模式

九、設計模式之裝飾器模式

十、設計模式之外觀模式

十一、外觀模式之享元模式

十二、設計模式之責任鏈模式

十三、設計模式之命令模式

十四、設計模式之直譯器模式

十五、設計模式之迭代器模式