1. 程式人生 > >設計模式的征途—22.中介者(Mediator)模式

設計模式的征途—22.中介者(Mediator)模式

我們都用過QQ,它有兩種聊天方式:一是私聊,二是群聊。使用QQ群,一個使用者就可以向多個使用者傳送相同的資訊和檔案,從而無需一一發送,節省大量時間。通過引入群的機制,極大地減少系統中使用者之間的兩兩通訊,使用者與使用者之間的聯絡可以通過群的機制來實現。

在有些軟體中,某些類/物件之間的相互呼叫關係錯綜複雜,類似於QQ使用者之間的關係,此時,特別需要一個類似“QQ群”一樣的中間類來協調這些類/物件之間的複雜關係,以降低系統的耦合度。因此,一個設計模式因此誕生,它就是中介者模式。

中介者模式(Mediator) 學習難度:★★★☆☆ 使用頻率:★★☆☆☆

一、客戶資訊管理模組的初始設計

1.1 需求背景

Background:M公司欲開發一套CRM系統,其中包含一個客戶資訊管理模組,所涉及的“客戶資訊管理視窗”介面效果圖如下圖所示:

M公司開發人員通過分析發現,在上圖中,介面元件之間存在較為複雜的互動關係:如果刪除一個客戶,則將從客戶列表中刪掉對應的項,客戶選擇組合框中客戶名稱也稱將減少一個;如果增加一個客戶資訊,則客戶列表中將增加一個客戶,且組合框中也將增加一項。  

1.2 初始設計

  M公司開發人員針對元件之間的互動關係進行了分析,發現:

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

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

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

  根據互動關係,開發人員繪製瞭如下圖所示的初始類圖。

  不難發現,上述設計存在以下問題:

  (1)系統結構負責且耦合度高 => 複雜的網狀結構,OMG!

  (2)元件的可重用性差 =>  由於每一個元件和其他元件之間都具有很強的關聯,很難重用!

  (3)系統的擴充套件性差 => 如果在上述系統中增加一個新的元件類,必須修改與之互動的各個元件原始碼!

二、中介者模式概述

2.1 中介者模式簡介

  如果在一個系統中物件之間存在多對多的相互關係,可以將物件之間的一些互動行為從各個物件中分離出來,並集中封裝在一箇中介者物件中,並由該中介者進行統一協調,這樣物件之間多對多的複雜關係就轉化為了相對簡單的一對多關係。通過引入中介者來簡化物件之間的複雜關係,它是迪米特法則的一個典型應用。

中介者(Mediator)模式:用一箇中介物件來封裝一系列的物件互動,中介者使各物件不需要顯示地相互引用,從而使其耦合鬆散,而且可以相對獨立地改變它們之間的互動。中介者模式又稱為調停模式,它是一種物件行為型模式。  

2.2 中介者模式結構

  在中介者模式中,引入了用於協調其他物件/類之間的相互呼叫的中介者類,為了讓系統具有更好的靈活性和可擴充套件性,通常還提供了抽象中介者,其結構圖如下圖所示:

  中介者模式結構圖中主要包含以下4個角色:

  (1)Mediator(抽象中介者):它定義了一個介面,該介面用於與各同事物件之間進行通訊。

  (2)ConcreteMediator(具體中介者):它實現了介面,通過協調各個同事物件來實現協作行為,維持了各個同事物件的引用。

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

  (4)ConcreteColleague(具體同事類):抽象同事類的子類,每一個同事物件需要和其他物件通訊時,都需要先與中介者物件通訊,通過中介者來間接完成與其他同事類的通訊。

三、客戶資訊管理模組的重構實現

3.1 重構後的設計結構

  M公司開發人員藉助中介者模式來重新設計結構如下圖所示:

  在具體實現時,為了確保系統有更好的靈活性和可擴充套件性,需要定義抽象中介者和抽象元件類,其中抽象元件類是所有具體元件類的公共父類,完整類圖如下圖所示:

  其中,Component充當抽象同事類,Button,List,ComboBox和TextBox充當具體同事類,Mediator充當抽象中介者類,ConcreteMediator充當具體中介類。在ConcreteMediator中維持了對具體同事物件的引用,為了簡化ConcreteMediator類的程式碼,在其中只定義了一個Button物件和TextBox物件。

3.2 重構後的程式碼實現

  (1)抽象中介者:Mediator

    /// <summary>
    /// 抽象中介者
    /// </summary>
    public abstract class Mediator
    {
        public abstract void ComponenetChanged(Component c);
    }

  (2)具體中介者:ConcreteMediator

    /// <summary>
    /// 具體中介者
    /// </summary>
    public class ConcreteMediator : Mediator
    {
        // 維持對各個同事物件的引用
        public Button addButton;
        public List list;
        public TextBox userNameTextBox;
        public ComboBox cb;

        // 封裝同事物件之間的互動
        public override void ComponenetChanged(Component c)
        {
            // 單擊按鈕
            if (c == addButton)
            {
                Console.WriteLine("-- 單擊增加按鈕 --");
                list.Update();
                cb.Update();
                userNameTextBox.Update();
            }
            // 從列表框選擇客戶
            else if (c == list)
            {
                Console.WriteLine("-- 從列表框選擇客戶 --");
                cb.Select();
                userNameTextBox.SetText();
            }
            // 從組合框選擇客戶
            else if (c == cb)
            {
                Console.WriteLine("-- 從組合框選擇客戶 --");
                cb.Select();
                userNameTextBox.SetText();
            }
        }
    }

  (3)抽象同事類:Colleague

    /// <summary>
    /// 抽象同事類:抽象元件
    /// </summary>
    public abstract class Component
    {
        protected Mediator mediator;

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

        // 轉發呼叫
        public void Changed()
        {
            mediator.ComponenetChanged(this);
        }

        public abstract void Update();
    }

  (4)具體同事類:ConcreteColleague

    /// <summary>
    /// 具體同事類:按鈕元件
    /// </summary>
    public class Button : Component
    {
        public override void Update()
        {
            // 按鈕不產生響應
        }
    }

    /// <summary>
    /// 具體同事類:列表框元件
    /// </summary>
    public class List : Component
    {
        public override void Update()
        {
            Console.WriteLine("列表框增加一項:張無忌");
        }

        public void Select()
        {
            Console.WriteLine("列表框選中項:小龍女");
        }
    }

    /// <summary>
    /// 具體同事類:組合框元件
    /// </summary>
    public class ComboBox : Component
    {
        public override void Update()
        {
            Console.WriteLine("組合框增加一項:張無忌");
        }

        public void Select()
        {
            Console.WriteLine("組合框選中項:小龍女");
        }
    }

    /// <summary>
    /// 具體同事類:文字框元件
    /// </summary>
    public class TextBox : Component
    {
        public override void Update()
        {
            Console.WriteLine("客戶資訊增加成功後文本框清空");
        }

        public void SetText()
        {
            Console.WriteLine("文字框顯示:小龍女");
        }
    }

    /// <summary>
    /// 具體同事類:標籤元件
    /// </summary>
    public class Label : Component
    {
        public override void Update()
        {
            Console.WriteLine("文字標籤內容改變,客戶資訊總數量加1");
        }
    }

  (5)客戶端測試:

    public class Program
    {
        public static void Main()
        {
            // Step1.定義中介者物件
            ConcreteMediator mediator = new ConcreteMediator();

            // Step2.定義同事物件
            Button addButton = new Button();
            List list = new List();
            ComboBox cb = new ComboBox();
            TextBox userNameTextBox = new TextBox();

            addButton.SetMediator(mediator);
            list.SetMediator(mediator);
            cb.SetMediator(mediator);
            userNameTextBox.SetMediator(mediator);

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

            // Step3.點選增加按鈕
            addButton.Changed();

            Console.WriteLine("---------------------------------------------");

            // Step4.從列表框選擇客戶
            list.Changed();
        }
    }

  除錯執行後的結果如下所示:

  

四、中介者模式小結

4.1 主要優點

  (1)簡化了物件之間的互動,它用中介者和同事的一對多互動替代了原來同事之間的多對多互動

  (2)將各同事物件解耦,可以獨立地改變和複用每個同事和中介者,增加新的中介和同事很方便,符合開閉原則。

  (3)可以減少大量同事子類的生成,改變同事行為只需要生成新的中介者子類即可。

4.2 主要缺點

  具體中介者子類中包含了大量的同事之間的互動細節,可能會導致具體中介者類非常複雜,使得系統難以維護。

4.3 應用場景

  (1)系統中物件之間存在複雜的引用關係 => 系統結構混亂且難以理解

  (2)一個物件由於引用了其他很多物件並且直接和這些物件通訊 => 難以複用該物件

  (3)想要通過一箇中間類來封裝多個類的行為又不想生成太多子類 => 引入中介者即可實現

參考資料

  DesignPattern

  (1)劉偉,《設計模式的藝術—軟體開發人員內功修煉之道》

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

設計模式征途22.中介Mediator模式

我們都用過QQ,它有兩種聊天方式:一是私聊,二是群聊。使用QQ群,一個使用者就可以向多個使用者傳送相同的資訊和檔案,從而無需一一發送,節省大量時間。通過引入群的機制,極大地減少系統中使用者之間的兩兩通訊,使用者與使用者之間的聯絡可以通過群的機制來實現。 在有些軟體中,某些類/物件之間的相互呼叫關係錯綜複

設計模式征途—6.建造Builder模式

建造者模式又稱為生成器模式,它是一種較為複雜、使用頻率也相對較低的建立型模式。建造者模式為客戶端返回的不是一個簡單的產品,而是一個由多個部件組成的複雜產品。因為,沒有人買車會只買一個方向盤或者輪胎,大家買的都是一輛包含輪胎、方向盤和發動機等多個部件組成的完整汽車。如何將這些部件組裝成一輛完整的汽車並返回給使用

設計模式征途—15.觀察Observer模式

在日常生活中,交通訊號燈指揮者日益擁擠的城市交通。紅燈亮,汽車停止;綠燈亮,汽車繼續前行;在這個過程中,交通訊號燈是汽車的觀察目標,而汽車則是觀察者。隨著交通訊號燈的變化,汽車的行為也會隨之變化,一盞交通訊號燈可以指揮多輛汽車。在軟體系統中,有些物件之間也存在類似交通訊號燈和汽車之間的關係,一個物件的狀態或行

【java設計模式】之 建造Builder模式

        我們還是舉上一節的例子:生產汽車。上一節我們通過模板方法模式控制汽車跑起來的動作,那麼需求是無止境的,現在如果老闆又增加了額外的需求:汽車啟動、停止、鳴笛引擎聲都由客戶自己控制,他想要什麼順序就什麼順序,那該如何做呢? 1. 汽車無休止的改造       

設計模式征途—23.解釋器Interpreter模式

args 參考資料 轉載 返回 下一個 tle title 缺點 images 雖然目前計算機編程語言有好幾百種,但有時人們還是希望用一些簡單的語言來實現特定的操作,只需要向計算機輸入一個句子或文件,就能按照預定的文法規則來對句子或文件進行解釋。例如,我們想要只輸入一個加法

設計模式:觀察Observer模式

image 強制轉換 trace vat PE sta obs observer -a 設計模式:觀察者(Observer)模式 一、前言 觀察者模式其實最好的名稱應該是“發布訂閱”模式,和我們現在大數據之中的發布訂閱方式比較類似,但是也有區別的地方,在上一個設計模式,

設計模式之裝飾Decorator模式

首先來看一個場景,如圖: 工人分為很多種類,比如電工,管道工等等,同時又有A公司的電工,B公司的電工,A公司的管道工,B公司的管道工等等,那麼當有M個工種和N個公司的時候,就會有 M * N 個子類,這個繼承體系就會變得很龐大和複雜。那麼如何簡化呢,那麼

設計模式征途—1.單例Singleton模式

  單例模式屬於建立型模式的一種,建立型模式是一類最常用的設計模式,在軟體開發中應用非常廣泛。建立型模式將物件的建立和使用分離,在使用物件時無需關心物件的建立細節,從而降低系統的耦合度,讓設計方案更易於修改和擴充套件。每一個建立型模式都在檢視回答3個問題:3W -> 建立什麼(What)、由誰建立(Wh

設計模式征途—8.橋接Bridge模式

在現實生活中,我們常常會用到兩種或多種型別的筆,比如毛筆和蠟筆。假設我們需要大、中、小三種類型的畫筆來繪製12中不同的顏色,如果我們使用蠟筆,需要準備3*12=36支。但如果使用毛筆的話,只需要提供3種型號的毛筆,外加12個顏料盒即可,涉及的物件個數僅為3+12=15,遠遠小於36卻能實現與36支蠟筆同樣的功

設計模式征途—12.享元Flyweight模式

現在在大力推行節約型社會,“浪費可恥,節儉光榮”。在軟體系統中,有時候也會存在資源浪費的情況,例如,在計算機記憶體中儲存了多個完全相同或者非常相似的物件,如果這些物件的數量太多將導致系統執行代價過高。那麼,是否存在一種技術可以用於節約記憶體使用空間,實現對這些相同或者相似物件的共享訪問呢?答案是肯定的,這種技

設計模式】module模式&&Revealing module 揭示模式

但是 出版 參數傳遞 9.png 自然 指向 們的 private 初級 寫在前面 《head first設計模式》裏有一篇文章,是說使用模式的心智,   1、初學者"心智" :"我要為HELLO WORLD找個模式"   2、中級人員模式: "或許這裏我需要一個單件

【java設計模式】之 單例Singleton模式

1. 單例模式的定義         單例模式(Singleton Pattern)是一個比較簡單的模式,其原始定義如下:Ensure a class has only one instance, and provide a global point of access

程式設計模式(十二) C++ 代理Proxy模式

2.7 Proxy 代理模式為其他物件提供一種代理以控制對這個物件的訪問。 在需要用比較通用和複雜的物件指標代替簡單的的指標的時候,使用代理模式。有四種常用的情況:        1、遠端代理,也就是為一個物件在不同的地址空間提供區域性代表。這樣可以隱藏一個物件存在於不

設計模式---接口隔離模式中介模式Mediator

單向 com clas 分享 分享圖片 獨立 mage 分解 pan 一:概念 在Mediator模式中,類之間的交互行為被統一放在Mediator的對象中,對象通過Mediator對象同其他對象交互。Mediator對象起到控制器的作用 二:動機 在軟件

設計模式-中介模式Mediator

中介者模式是行為型模式的一種,在Mediator中,類之間的互動行為被統一放在Mediator物件中,物件通過Mediator物件同其他物件互動。 角色和職責: 1.中介者介面(Mediator):    中介者類的抽象父類 2.具體中介者(Concrete Mediator) -

設計模式--中介模式Mediator

 本文是設計模式學習筆記的第三篇文章,主要分析的是中介者模式。是清華大學出版社的《研讀設計模式》的讀書筆記。在此感謝原作者。 這次應用的是一個例項去理解中介者模式。 先來看這樣一個例項,電腦播放電影。 我們需要一個DVD,然後放入播放器中,播放器獲得資料傳遞給CPU

設計模式入門——中介模式mediator

前言 中介者模式又稱為調停者模式,作為行為型的模式之一,本身是個很低調的模式,因為應用場合有限,所以不那麼被人熟知 下文我將舉例介紹中介者模式的作用,以及中介者模式應用的意義,文末我會總結一下中介者模式的一些特點 例項引入        假設現在科技發達之

GoF之中介模式Mediator

耦合度 自己 sed ets 引用 def 獨立性 rip clas 定義   定義一個接口用來封裝一群對象的互動行為,中介者通過移除對象之間的引用,來減少他們之間的耦合,並且能改變他們之間的互動獨立性。     整合系統功能,減少系統內部的耦合度。與Facade

23、行為型-中介模式Mediator

中介者模式(Mediator Pattern):用一箇中介物件(中介者)來封裝一系列的物件互動,中介者使各物件不需要顯式地相互引用

設計模式系列之中介模式(Mediator Pattern)——協調多個物件之間的互動

說明:設計模式系列文章是讀`劉偉`所著`《設計模式的藝術之道(軟體開發人員內功修煉之道)》`一書的閱讀筆記。個人感覺這本書講的不錯,有興趣推薦讀一讀。詳細內容也可以看看此書作者的部落格`https://blog.csdn.net/LoveLion/article/details/17517213` ## 模