設計模式 | 中介者模式(詳解)

中介者模式

案例介紹:

編寫信息管理模塊:

界面組件之間存在較爲複雜的交互關係:如果刪除一個客戶,要在客戶列表(List)中刪掉對應的項,客戶選擇組合框(ComboBox)中客戶名稱也將減少一個;如果增加一個客戶信息,客戶列表中需增加一個客戶,且組合框中也將增加一項。
如果實現界面組件之間的交互一個問題?

(1) 當用戶單擊“增加”按鈕、“刪除”按鈕、“修改”按鈕或“查詢”按鈕時,界面左側的“客戶選擇組合框”、“客戶列表”以及界面中的文本框將產生響應。

(2) 當用戶通過“客戶選擇組合框”選中某個客戶姓名時,“客戶列表”和文本框將產生響應。

(3) 當用戶通過“客戶列表”選中某個客戶姓名時,“客戶選擇組合框”和文本框將產生響應。

於是開發人員根據組件之間的交互關係繪製瞭如圖20-3所示初始類圖:
在這裏插入圖片描述

設計方案存在如下問題:
(1) 系統結構複雜且耦合度高:每一個界面組件都與多個其他組件之間產生相互關聯和調用,若一個界面組件對象發生變化,需要跟蹤與之有關聯的其他所有組件並進行處理,系統組件之間呈現一種較爲複雜的網狀結構,組件之間的耦合度高。

(2) 組件的可重用性差:由於每一個組件和其他組件之間都具有很強的關聯,若沒有其他組件的支持,一個組件很難被另一個系統或模塊重用,這些組件表現出來更像一個不可分割的整體,而在實際使用時,我們往往需要每一個組件都能夠單獨重用,而不是重用一個由多個組件組成的複雜結構。

(3) 系統的可擴展性差:如果在上述系統中增加一個新的組件類,則必須修改與之交互的其他組件類的源代碼,將導致多個類的源代碼需要修改,同樣,如果要刪除一個組件也存在類似的問題,這違反了“開閉原則”,可擴展性和靈活性欠佳。

由於存在上述問題,Sunny公司開發人員不得不對原有系統進行重構,那如何重構呢?大家想到了“迪米特法則”,引入一個“第三者”來降低現有系統中類之間的耦合度。由這個“第三者”來封裝並協調原有組件兩兩之間複雜的引用關係,使之成爲一個鬆耦合的系統,這個“第三者”又稱爲“中介者”,中介者模式因此而得名。

你中有我,我中有你,不利於鬆耦合

中介者模式基本介紹

  1. 中介者模式(Mediator Pattern),用一箇中介對象來封裝一系列的對象交互。
    中介者使各個對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立
    地改變它們之間的交互
  2. 中介者模式屬於行爲型模式,使代碼易於維護
  3. 比如MVC模式,C(Controller控制器)是M(Model模型)和V(View視圖)的中介者,在前後端交互時起到了中間人的作用

對象之間存在大量的多對多聯繫,將導致系統非常複雜,這些對象既會影響別的對象,也會被別的對象所影響,這些對象稱爲同事對象,它們之間通過彼此的相互作用實現系統的行爲。在網狀結構中,幾乎每個對象都需要與其他對象發生相互作用,而這種相互作用表現爲一個對象與另外一個對象的直接耦合,這將導致一個過度耦合的系統

中介者模式是“迪米特法則”的一個典型應用。

中介者模式類圖:

在這裏插入圖片描述

中介者模式角色:

Mediator(抽象中介者):它定義一個接口,該接口用於與各同事對象之間進行通信。

ConcreteMediator(具體中介者):它是抽象中介者的子類,通過協調各個同事對象來實現協作行爲,它維持了對各個同事對象的引用。

Colleague(抽象同事類):它定義各個同事類公有的方法,並聲明瞭一些抽象方法來供子類實現,同時它維持了一個對抽象中介者類的引用,其子類可以通過該引用來與中介者通信。

ConcreteColleague(具體同事類):它是抽象同事類的子類;每一個同事對象在需要和其他同事對象通信時,先與中介者通信,通過中介者來間接完成與其他同事類的通信;在具體同事類中實現了在抽象同事類中聲明的抽象方法。

中介者類承擔了兩方面的職責:

(1) 中轉作用(結構性):通過中介者提供的中轉作用,各個同事對象就不再需要顯式引用其他同事,當需要和其他同事進行通信時,可通過中介者來實現間接調用。該中轉作用屬於中介者在結構上的支持。

(2) 協調作用(行爲性):中介者可以更進一步的對同事之間的關係進行封裝,同事可以一致的和中介者進行交互,而不需要指明中介者需要具體怎麼做,中介者根據封裝在自身內部的協調邏輯,對同事的請求進行進一步處理,將同事成員之間的關係行爲進行分離和封裝。該協調作用屬於中介者在行爲上的支持。

代碼實現:

抽象組件類;抽象同事類

`
public abstract class Component {
    protected  Mediator mediator;

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
    public void changed (){
    mediator.componentChanged(this);
    }
    public abstract void update();
}

具體同事類: 按鈕組件

/**
 * @author 孫一鳴 on 2020/2/20
 */
public class MyButton extends Component{
    @Override
    public void update() {
    //按鈕不產生交互
    }
}

具體同事類:組合框類

/**
 * 組合框類:具體同事類
 * @author 孫一鳴 on 2020/2/20
 */
public class MyComboBox extends Component {


    public void update() {
        System.out.println("組合框增加一項:比爾蓋茨。");
    }

    public void select() {
        System.out.println("組合框選中項:馬雲");

    }
}

具體同事類:列表框類

/**
 * 列表框類:具體同事類
 * @author 孫一鳴 on 2020/2/20
 */
public class MyList extends  Component{
    @Override
    public void update() {
        System.out.println("列表框新加同事:比爾蓋茨");
    }

    public void select (){
        System.out.println("列表框選中項:馬雲");
    }
}

具體同事類:文本框類

/**
 * //文本框類:具體同事類
 *
 * @author 孫一鳴 on 2020/2/20
 */
public class MyTextBox extends Component {
    public void update() {
        System.out.println("客戶信息增加成功後文本框清空。");
    }

    public void setText() {
        System.out.println("文本框顯示:馬雲");

    }
}

抽象中介者類:


/**
 *
 //抽象中介者
 * @author 孫一鳴 on 2020/2/20
 */
public abstract class Mediator {
    public  abstract  void componentChanged(Component c);
}

具體中介者類:


/**
 * 具體中介者
 *
 * @author 孫一鳴 on 2020/2/20
 */
public class ConcreteMediator extends Mediator{
    //維持對多個同事對象的引用
    public MyButton addButton;
    public MyList list;
    public MyTextBox userNameTextBox;
    public MyComboBox cb;


    //封裝同事對象之間的交互

    @Override
    public void componentChanged(Component c) {
        //單擊按鈕
        if(c == addButton) {
            System.out.println("--單擊增加按鈕--");
            list.update();
            cb.update();
            userNameTextBox.update();
        }
        //從列表框選擇客戶
        else if(c == list) {
            System.out.println("--從列表框選擇客戶--");
            cb.select();
            userNameTextBox.setText();
        }
        //從組合框選擇客戶
        else if(c == cb) {
            System.out.println("--從組合框選擇客戶--");
            cb.select();
            userNameTextBox.setText();
        }

    }
}

測試類:


/**
 * @author 孫一鳴 on 2020/2/20
 */
public class Client {
    public static void main(String args[]) {
        //定義中介者對象
        ConcreteMediator mediator;
        mediator = new ConcreteMediator();

        //定義同事對象
        MyButton addBT = new MyButton();
        MyList list = new MyList();
        MyComboBox cb = new MyComboBox();
        MyTextBox userNameTB = new MyTextBox();

        addBT.setMediator(mediator);
        list.setMediator(mediator);
        cb.setMediator(mediator);
        userNameTB.setMediator(mediator);

        mediator.addButton = addBT;
        mediator.list = list;
        mediator.cb = cb;
        mediator.userNameTextBox = userNameTB;

        addBT.changed();
        System.out.println("-----------------------------");
        list.changed();

    }
}

結果截圖:

在這裏插入圖片描述

中介者模式的注意事項和細節

  1. 多個類相互耦合,會形成網狀結構, 使用中介者模式將網狀結構分離星型結構,進行解耦
  2. 減少類間依賴,降低了耦合,符合迪米特原則
  3. 中介者承擔了較多的責任,一旦中介者出現了問題,整個系統就會受到影響
  4. 如果設計不當,中介者對象本身變得過於複雜,這點在實際使用時,要特別注意

本文參考鏈接:https://blog.csdn.net/lovelion/article/details/8483081
版權聲明:本文爲CSDN博主「LoveLion」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章