面向對象編程思想-中介者模式

来源:http://www.cnblogs.com/jdzhang/archive/2017/08/21/7405736.html
-Advertisement-
Play Games

一、引言 前兩天休息日在網上打QQ鬥地主,每盤結束後騰訊游戲平臺會自動計算輸贏的歡樂豆,嗯?挺好的,平時在面對面玩鬥地主時,一盤游戲結束後,我們需要瞭解每個人的出牌狀況,然後算出來輸贏。現在有了游戲平臺,玩家之間計算輸贏這個操作交給了游戲平臺,我們不再需要瞭解每個人的出牌狀況。在軟體設計中,我們將解 ...


一、引言

前兩天休息日在網上打QQ鬥地主,每盤結束後騰訊游戲平臺會自動計算輸贏的歡樂豆,嗯?挺好的,平時在面對面玩鬥地主時,一盤游戲結束後,我們需要瞭解每個人的出牌狀況,然後算出來輸贏。現在有了游戲平臺,玩家之間計算輸贏這個操作交給了游戲平臺,我們不再需要瞭解每個人的出牌狀況。在軟體設計中,我們將解決這種業務場景的模式稱之為中介者模式

二、中介者模式

定義:用一個中介對象來封裝一系列對象的交互。中介者使各對象不需要顯式的相互引用,從而使其耦合鬆散,而且獨立改變它們之間的交互。

下麵是中介者模式結構圖:

為什麼要使用中介者模式?

如果不使用中介者模式,各個同事對象將相互引用,如果每個對象都與多個對象交互時,將形成下圖所示網狀結構:

分析:上圖中每個對象之間過度耦合,不利於類的復用也不利於擴展。假如對象一變化了將可能引起與它直接相依賴的所有對象的調整,所以同事對象之間直接依賴不是好的設計。

如果採用中介者模式,那麼對象之間的關係將變成下圖所示星型結構;

分析:使用中介者模式後,任何一個同事對象的變化,只會影響中介者和類本身,不會像之前設計中一個對象變化,將會引用所有與之關聯的對象變化

場景:兩個人本金都是100,在一起打牌,每盤結束後計算兩個人的金額

下麵是不使用中介者模式的demo:

     //抽象同事類  充當牌友類
    public abstract class Colleague
    {
        public int Number
        {
            get;
            set;
        }
        public abstract void Win(int number, Colleague colleague);
    }
    //牌友A類
    public class ConcreteColleagueA : Colleague
    {
        public override void Win(int number, Colleague colleague)
        {
            this.Number += number;
            colleague.Number -= number;
        }      
    }
    //牌友B類
    class ConcreteColleagueB : Colleague
    {
        public override void Win(int number, Colleague colleague)
        {
            this.Number += number;
            colleague.Number -= number;
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            //A和B兩個人打牌
            Colleague colleagueA = new ConcreteColleagueA();
            Colleague colleagueB = new ConcreteColleagueB();
            colleagueA.Number = 100;
            colleagueB.Number = 100;
            //A贏了B就輸錢
            colleagueA.Win(5, colleagueB);
            Console.WriteLine($"A的數量為{colleagueA.Number}");
            Console.WriteLine($"B的數量為{colleagueA.Number}");

            Console.Read();
        }
    }
View Code

分析:上述確實解決了場景中的問題,牌友A和牌友B都依賴於抽象,從而降低同事類之間的耦合度。這樣的設計中,牌友A的變化會引起牌友B的變化,但是如果現在要新增一個牌友C、D、E呢?設計到多個對象的變化時,當前同事類需要瞭解其他所有涉及的同事類狀況,這時就需要修改同事類了,而且,多個牌友計算輸贏時任何一個人計算錯誤,都會導致整個業務場景中的計算錯誤。基於此思考,能不能把計算的錢的任務交給程式做呢?譬如QQ鬥地主。。。即引入中介者對象來協調各個對象之間的關係

下麵是引入中介者對象的代碼demo

//抽象同事類
    public abstract class Colleague
    {
        public int Number
        {
            get;
            set;
        }
        public abstract void Win(int number, Mediator mediator);
    }
     //抽象中介者類
    public abstract class Mediator
    {
        public ConcreteColleagueA A;
        public ConcreteColleagueB B;
        public Mediator(ConcreteColleagueA a, ConcreteColleagueB b)
        {
            A = a;
            B = b;
        }
        public abstract void AWin(int number);
        public abstract void BWin(int number);
    }
    public class ConcreteColleagueA : Colleague
    {
        public override void Win(int number, Mediator mediator)
        {
            mediator.AWin(number);
        }
    }
     public class ConcreteColleagueB : Colleague
    {
        public override void Win(int number, Mediator mediator)
        {
            mediator.BWin(number);
        }
    }
    class ConcreteMediator : Mediator
    {
        public ConcreteMediator(ConcreteColleagueA a, ConcreteColleagueB b) : base(a,b)
        { }

        public override void AWin(int number)
        {
            A.Number += number;
            B.Number -= number;
        }
        public override void BWin(int number)
        {
            A.Number -= number;
            B.Number += number;
        }
     }   
    class Program
    {
        static void Main(string[] args)
        {
            ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA();
            ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB();
            ConcreteMediator concreteMediator = new ConcreteMediator(concreteColleagueA, concreteColleagueB);
            concreteColleagueA.Number = 100;
            concreteColleagueB.Number = 100;
            concreteMediator.AWin(5);
            Console.WriteLine($"A的數量為{concreteColleagueA.Number}");
            Console.WriteLine($"B的數量為{concreteColleagueB.Number}");
            Console.WriteLine();
            Console.Read();
        }
    }  
View Code

分析:運行結果和上面不使用中介者模式的代碼運行結果一致,這樣如果某個牌友類變化時,只會影響到該變化的牌友類和中介者類,從而解決上面代碼中的問題。

但是此時如果要新增一個牌友類,我們就不得不修改抽象中介者類,還可以再完善一下嗎?完全可以,我們可以結合觀察者模式,在抽象中介者類中保存一個抽象牌友類的集合,添加保存刪除牌友的方法管理集合,然後在具體的中介者類中,修改AWin()、BWin()迴圈遍歷執行改變自己和其他牌友的錢數。此時仍然存在一個問題,新增牌友時,我們雖然不需要修改抽象中介者類,但是還是要在具體中介者類中添加CWin()方法,這時可以此採用狀態模式來解決問題,具體會在下一個專題中介紹。

下麵是大話設計模式中的例子輔助理解中介者模式:

    abstract class Colleague
    {
        protected Mediator mediator;
        public Colleague(Mediator mediator)
        {
            this.mediator = mediator;
        }
    }
    abstract class Mediator
    {
        public abstract void Send(string message, Colleague colleague);
    }
     class ConcreteColleagueA : Colleague
    {
        public ConcreteColleagueA(Mediator mediator) : base(mediator)
        {

        }
        public void Send(string message)
        {
            mediator.Send(message, this);
        }
        public void Notify(string message)
        {
            Console.WriteLine("同事A得到消息:"+message);
        }
    }
     class ConcreteColleagueB : Colleague
    {
        public ConcreteColleagueB(Mediator mediator) : base(mediator)
        {

        }
        public void Send(string message)
        {
            mediator.Send(message, this);
        }
        public void Notify(string message)
        {
            Console.WriteLine("同事B得到消息:" + message);
        }
    }
    class ConcreteMediator : Mediator
    {
        private ConcreteColleagueA concreteColleagueA;
        private ConcreteColleagueB concreteColleagueB;
        public ConcreteColleagueA ConcreteColleagueA
        {
            set { concreteColleagueA = value; }
        }
        public ConcreteColleagueB ConcreteColleagueB
        {
            set { concreteColleagueB = value; }
        }
        public override void Send(string message, Colleague colleague)
        {
            if(colleague==concreteColleagueA)
            {
                concreteColleagueB.Notify(message);
            }
            else if(colleague==concreteColleagueB)
            {
                concreteColleagueA.Notify(message);
            }
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            ConcreteMediator concreteMediator = new ConcreteMediator();
            ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA(concreteMediator);
            ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB(concreteMediator);
            concreteMediator.ConcreteColleagueA = concreteColleagueA;
            concreteMediator.ConcreteColleagueB = concreteColleagueB;
            concreteColleagueA.Send("你吃過飯了嗎?");
            concreteColleagueB.Send("我吃過了");
            Console.Read();
        }
    }
View Code

優點:

1.將系統各個對象之間的關係進行封裝,將各個同事類解耦,使系統松耦合

2.將對象間一對多關係轉變為一對一關聯,使對象間關係易於理解和維護

3.提高系統靈活性,使各個同事類獨立而易於復用

缺點:

1.中介者承擔的責任太重,一旦中介者出現問題,整個系統將會受到影響

2.新增加一個同事類時,不得不修改抽象中介者類和具體的中介者類

適用場景:

1.一組定義好的關係,要進行複雜的通信(如最開始對象間關係成網狀結構)時,使用中介者模式可以使同事類間關係更清晰

2.想通過一個中間類來封裝多個類中的行為

 

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

參照:

1.大話設計模式

2.http://www.cnblogs.com/zhili/p/MediatorPattern.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • PHP程式員閱讀Java語言實現設計模式的書,然後用Go語言實現。配以現實生活中的實例,幫助理解設計模式。本篇包括:策略、觀察者、裝飾者、工廠、單例、命令、適配器、外觀。 ...
  • HTTP協議 自從入坑以來,只要是跟web打交道,總是免不了這個HTTP協議,這是什麼鬼,讓我們一探究竟。(不周之處還請賜教!!!) 既然是協議,我們首先要問三個問題,誰跟誰的協議?協議是什麼?怎麼用? 第一個問題: 誰跟誰的協議? 所謂協議,至少需要兩方,甲方and乙方,我們先說下甲方and乙方到 ...
  • 題目鏈接 Problem Description There is a set including all positive integers that are not more then n. HazelFan wants to choose some integers from this set ...
  • what's the 操作系統? 首先,我們要知道,為什麼要有操作系統。現代的電腦系統主要是由一個或者多個處理器,主存、硬碟、鍵盤、滑鼠、顯示器、印表機、網路介面及其他輸入輸出設備組成。現代電腦的組成部分極其複雜,我們不可能全部瞭解完再去寫開發,所以就需要用到操作系統。程式員只需要做自己的本職開 ...
  • @為什麼需要BaseServlet? 我們知道一個POST或者GET提交對應著一個Servlet, 無數的提交會讓Servlet頁面增加,我們希望一個Servlet就能處理很多提交的請求。 @BaseServlet 是一個繼承了HttpServlet的普通類,並不是Servlet類,所以不需要在we ...
  • 1、創建maven項目 版本:Java 1.8 Mysql 6.0 勾選 Create a simple project (不使用骨架) 註意選擇 maven-archetype-webapp 2)New Maven project 頁面 GroupID 是項目組織唯一的標識符,實際對應java的包 ...
  • 消息隊列是在樂視這邊非常普遍使用的技術。在我們部門內部,不同的項目使用的消息隊列實現也不一樣。下麵是支付系統的流轉圖(部門兄弟畫的,借用一下): 從圖中可以看到,裡面用到了kafka消息隊列。作用是做資料庫分庫分表後的聚合,非同步彙總到一張總表。裡面也用到了redis,用來處理高併發下的訂單重覆提交。 ...
  • SpringMVC是用步驟: - 加入 jar 包 – 在 web.xml 中配置 DispatcherServlet – 加入 Spring MVC 的配置文件 – 編寫處理請求的處理器,並標識為處理器 – 編寫視圖 SpringMVC具體使用步驟:1、在eclipse中創建一個動態web項目;1 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...