1. 程式人生 > >設計模式系列:中介者模式

設計模式系列:中介者模式

引入

1.案例:

假設計算機1,2,3,4之間要相互通訊。

2.面向實現程式設計方案:

類Computer1中要儲存類Computer2、類Computer3和類Computer4例項,才能呼叫Computer2、Computer3、Computer4方法中的Comunicate方法。
。。。
。。。
。。。
具體圖示如下:
這裡寫圖片描述

3.面向設計程式設計方案:

建立一箇中介者,保有類Computer1,類Computer2,類Computer3,類Computer4物件,每個Computer只需要跟中介者打交道,即可和其他的Computer通訊。具體的圖示如下:
這裡寫圖片描述

明顯可以看到面向設計的方案通過增加一層(中介層)可以明顯較少類間的耦合。

一.名稱

二.問題(為了解決什麼問題)

中介者模式適合於多個物件之間緊密耦合的情況,緊密耦合的標準是:在類圖中出現了蜘蛛網狀結構。在這種情況下一定考慮使用中介者模式,這有利於把蜘蛛網樹立成為星型結構,使原本複雜混亂的關係變得清晰簡單。生活中常見的例項是:媒體閘道器、中介服務(如鏈家中介)等。

三.解決方案(主要體現在uml和核心程式碼上)

定義:用一箇中介物件封裝一系列的物件互動,中介者使各物件不需要顯示地相互作用,從而使其耦合鬆散,而且可以獨立改變他們之間的互動。

其實中介者模式是一個解耦框架,主要是通過增加一層(中介層)來實現類間的解耦。

中介者模式體現的設計原則有:依賴倒置,開閉原則,迪米特法則,里氏替換原則。
抽象類與繼承——依賴倒置
抽象類——開閉原則
降低耦合——迪米特法則
抽象類——里氏替換原則

如果物件之間的聯絡呈現為網狀結構,存在大量的多對多聯絡,在網狀結構中,幾乎每個物件都需要與其他物件發生相互作用,而這種相互作用表現為一個物件與另外一個物件的直接耦合,這將導致一個過度耦合的系統。如果在一個系統中物件之間存在多對多的相互關係,我們可以將物件之間的一些互動行為從各個物件中分離出來,並集中封裝在一箇中介者物件中,並由該中介者進行統一協調,這樣物件之間多對多的複雜關係就轉化為相對簡單的一對多關係。通過引入中介者來簡化物件之間的複雜互動,中介者模式是“迪米特法則”的一個典型應用。

類圖
這裡寫圖片描述
時序圖
這裡寫圖片描述

其實狀態模式的Context就像一箇中介者,避免了各種state之間的互動,二把互動交給Context來處理。

四.例子

求租者 - 房屋出租中介 - 房東 的故事
同事類:

/**
 * Created by annuoaichengzhang on 16/4/4.
 * 求租者-房屋出租中介-房東
 */
public abstract class Person {
    protected Mediator mediator;
    protected String name;

    public Person(Mediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    protected abstract void sendMessage(String msg);

    protected abstract void getMessage(String msg);
}
/**
 * Created by annuoaichengzhang on 16/4/4.
 */
public class LandLord extends Person {
    public LandLord(Mediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    protected void sendMessage(String msg) {
        mediator.operation(this, msg);
    }

    @Override
    protected void getMessage(String msg) {
        System.out.println("房東" + super.name + "收到中介發來的訊息:" + msg);
    }
}
/**
 * Created by annuoaichengzhang on 16/4/4.
 */
public class Renter extends Person {
    public Renter(Mediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    protected void sendMessage(String msg) {
        super.mediator.operation(this, msg);
    }

    @Override
    protected void getMessage(String msg) {
        System.out.println("求租者" + super.name + "收到中介發來的資訊" + msg);
    }
}

中介者:


/**
 * Created by annuoaichengzhang on 16/4/4.
 */
public abstract class Mediator {
    protected List<Person> landlordList = new ArrayList<>();
    protected List<Person> renterList = new ArrayList<>();

    public void registerLandlord(Person landLord) {
        landlordList.add(landLord);
    }

    public void registerRenter(Person renter){
        renterList.add(renter);
    }

    public abstract void operation(Person person, String message);
}
/**
 * Created by annuoaichengzhang on 16/4/4.
 */
public class HouseMediator extends Mediator {
    @Override
    public void operation(Person person, String message) {
        // 如果是租房者,就把租房者的需求資訊傳遞給註冊了的房東們
        if (person instanceof Renter) {
            for (Person landlord : landlordList) {
                landlord.getMessage(message);
            }
        } else if (person instanceof LandLord) {
            // 如果是房東,就把房東的出租訊息傳遞給註冊了的求租者
            for (Person renter : renterList) {
                renter.getMessage(message);
            }
        }
    }
}

client:

/**
 * Created by annuoaichengzhang on 16/4/4.
 */
public class Client {
    public static void main(String[] args) {
        Mediator mediator = new HouseMediator();
        Person landlordA, landlordB, renter;
        landlordA = new LandLord(mediator, "房東a");
        landlordB = new LandLord(mediator, "房東b");

        renter = new Renter(mediator, "小呂");
        mediator.registerLandlord(landlordA);
        mediator.registerLandlord(landlordB);
        mediator.registerRenter(renter);

        renter.sendMessage("想在四惠東附近租套一居室,加個1500");
        landlordA.sendMessage("在四惠東附近有一套兩居室要出租,租金3000,聯絡電話0101010101001");
    }
}

執行結果:

房東房東a收到中介發來的訊息:想在四惠東附近租套一居室,加個1500
房東房東b收到中介發來的訊息:想在四惠東附近租套一居室,加個1500
求租者小呂收到中介發來的資訊在四惠東附近有一套兩居室要出租,租金3000,聯絡電話0101010101001
Process finished with exit code 0

五.效果(有啥優缺點)

優點:
1. 簡化了物件間的互動

缺點:
1. 在具體的中介類中包含了大量同事之間的互動細節,會導致中介類非常複雜,不易維護。

常見案例

qq群群聊

圖形介面類庫。該類庫包含若干預定義的窗格物件,例如textpane、listpane等,窗格之間不允許直接引用。基於該類庫的應用由一個包含一組窗格的視窗組成,視窗需要協調窗格之間的行為。