軟件設計模式學習(二十一)中介者模式


對於那些存在對象之間複雜交互關係的系統,中介者模式提供了一種簡化複雜交互的解決方案,即經過引入一箇中介者,將本來對象之間的兩兩交互轉化爲每一個對象與中介者之間的交互java


模式動機

以微信聊天爲例,能夠用戶與用戶直接聊天,也能夠經過微信羣聊天。前者的話,用戶要和別的用戶加爲好友,即用戶和用戶之間存在多對多關係,一個用戶若是要將相同的信息發送給全部其餘用戶,必須一個一個發送。而若是使用羣聊天,一個用戶能夠向多個用戶發送相同信息而無須一一進行發送,只需將信息發送到羣中便可,羣的做用就是將發送者所發送的信息轉發給每個接收者用戶。微信

在用戶與用戶直接聊天的設計方案中,用戶對象之間存在很強關聯性,將致使系統出現以下問題:app

  • 系統結構複雜
  • 對象可重用性差
  • 系統擴展混亂

根據單一職責原則,咱們應儘可能將對象細化,使其只負責單一職責。一個由不少對象構成的模塊,爲了減小對象兩兩之間複雜的引用關係,咱們須要使用中介者模式,這就是中介者模式的模式動機。ide


模式定義

用一箇中介對象來封裝一系列對象交互,中介者使各對象不需顯式地相互引用,從而使其耦合鬆散,並且能夠獨立改變它們之間的交互。中介者模式又稱調停者模式,它是一種對象行爲型模式。測試


模式結構

  1. Mediator(抽象中介者)this

    定義一個接口,該接口應用於各同事對象之間的通訊設計

  2. ConcreteMediator(具體中介者)code

    抽象中介類的子類,經過協調各個同事對象來實現協做行爲,瞭解並維護它對各個同事對象的引用。對象

  3. Colleague(抽象同事類)blog

    定義各同事的公有方法

  4. ConcreteColleague(具體同事類)

    每個同事對象都引用一箇中介者對象,每個同事對象在須要時和其餘同事對象通訊時,先與中介者通訊,經過中介者來間接完成與其餘同事的通訊


模式分析

經過引入中介者對象,能夠將系統的網狀結構變成以中介者爲中心的星狀結構。在這個形狀結構中,同事對象再也不直接與另外一個對象聯繫,它經過中介者對象與另外一個對象發生相互做用。

若是對象之間存在多對多的相互關係,能夠將對象之間的一些交互行爲從各個對象中分離出來,並集中封裝在一箇中介者對象中,並由該中介者進行通訊和協調,這樣對象間的多對多的複雜關係就能夠經過簡單的多對一關係實現,符合迪米特法則,即「只與你直接的朋友們通訊,並且只要可能,朋友數目越少越好」。

中介者承擔瞭如下兩方面的職責:

  • 中轉做用:經過中介者提供的中轉做用,各個同事對象不須要顯式引用其餘同事,當須要和其餘同事進行通訊時,經過中介者便可
  • 協調做用:中介者能夠更進一步對同事之間的關係進行封裝,同事一致地和中介者進行交互,而不須要指明中介者具體怎麼作。中介者根據封裝在自身內部的邏輯協調,對同事的請求進行進一步處理,將同事成員之間的關係行爲進行分離和封裝

模式實例之虛擬聊天室

某論壇會員經過聊天室進行信息交流,普通會員(CommonMember)能夠給其餘會員發送文本信息,鑽石會員(DiamondMember)既能夠給其餘會員發送文本信息,還能夠發送圖片信息。聊天室能夠對不雅字符進行過濾,能夠對發送圖片的大小進行控制。

  1. 抽象中介者類 AbstractChatroom(抽象聊天室類)

    public abstract class AbstractChatroom {
        // 註冊同事對象的方法
        public abstract void register(Member member);
        // 同事之間發送文本信息方法
        public abstract void sendText(String from, String to, String message);
        // 同事之間發送圖片信息
        public abstract void sendImage(String from, String to, String image);
    }
  2. 抽象同事類 Member(抽象會員類)

    public abstract class Member {
    	// 維持一個抽象中介者的引用,用於調用中介者的方法
        protected AbstractChatroom chatroom;
        protected String name;
    
        public Member(String name) {
            this.name = name;
        }
    
        public AbstractChatroom getChatroom() {
            return chatroom;
        }
    
        public void setChatroom(AbstractChatroom chatroom) {
            this.chatroom = chatroom;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    	
        // 因爲不一樣類型會員發送文本信息和圖片信息的方式不一樣
        // 所以對這兩個方法進行抽象聲明
        public abstract void sendText(String to, String message);
    
        public abstract void sendImage(String to, String image);
    
        public void receiveText(String from, String message) {
            System.out.println(from + "發送文本給" + this.name + ",內容爲:" + message);
        }
    
        public void receiveImage(String from, String image) {
            System.out.println(from + "發送圖片給" + this.name + ",內容爲:" + image);
        }
    }
  3. 具體中介者類 ChatGroup(具體聊天室類)

    import java.util.Hashtable;
    
    public class ChatGroup extends AbstractChatroom {
    	
        // 定義一個集合對象存儲須要發生交互的同事對象
        private Hashtable<String, Member> members = new Hashtable<String, Member>();
    	
        // 提供註冊方式,將同事對象加入集合中
        @Override
        public void register(Member member) {
            if (!members.contains(member)) {
                members.put(member.getName(), member);
                member.setChatroom(this);
            }
        }
    
        @Override
        public void sendText(String from, String to, String message) {
            Member member = members.get(to);
            String newMessage = message;
            //  模擬不雅字符過濾
            newMessage = message.replace("日", "*");
            // 調用會員接收方法
            member.receiveText(from, newMessage);
        }
    
        @Override
        public void sendImage(String from, String to, String image) {
            Member member = members.get(to);
            //  模擬圖片大小判斷
            if (image.length() > 5) {
                System.out.println("圖片太大,發送失敗");
            } else {
                // 調用會員接收方法
                member.receiveImage(from, image);
            }
        }
    }
  4. 具體同事類 CommonMember(普通會員類)

    public class CommonMember extends Member {
    
        public CommonMember(String name) {
            super(name);
        }
    
        @Override
        public void sendText(String to, String message) {
            System.out.println("普通會員發送信息:");
            chatroom.sendText(name, to, message);
        }
    
        @Override
        public void sendImage(String to, String image) {
            System.out.println("普通會員不能發送圖片!");
        }
    }
  5. 具體同事類 DiamondMember(鑽石會員類)

    public class DiamondMember extends Member {
    
        public DiamondMember(String name) {
            super(name);
        }
    
        @Override
        public void sendText(String to, String message) {
            System.out.println("鑽石會員發送信息:");
            chatroom.sendText(name, to, message);
        }
    
        @Override
        public void sendImage(String to, String image) {
            System.out.println("鑽石會員發送圖片");
            chatroom.sendImage(name, to, image);
        }
    }
  6. 客戶端測試類 Client

    public class Client {
    
        public static void main(String[] args) {
    
            AbstractChatroom happyChat = new ChatGroup();
    
            Member member1, member2, member3, member4, member5;
            member1 = new DiamondMember("張三");
            member2 = new DiamondMember("李四");
            member3 = new CommonMember("王五");
            member4 = new CommonMember("小芳");
            member5 = new CommonMember("小紅");
    
            happyChat.register(member1);
            happyChat.register(member2);
            happyChat.register(member3);
            happyChat.register(member4);
            happyChat.register(member5);
    
            member1.sendText("李四", "李四,你好");
            member2.sendText("張三", "張三,你好");
            member1.sendText("李四", "今每天氣不錯,有日");
            member2.sendImage("張三", "一個很大很大的太陽");
            member2.sendImage("張三", "太陽");
            member3.sendText("小芳", "還有問題嗎?");
            member3.sendText("小紅", "還有問題嗎?");
            member4.sendText("王五", "沒有了,謝謝");
            member5.sendText("王五", "我也沒有了");
            member5.sendImage("王五", "謝謝");
        }
    }
  7. 運行結果

若是須要增長新的具體中介類,只需繼承抽象中介者類並實現其中方法便可,新的具體中介者類能夠對信息進行不一樣的處理,客戶端只需修改少許代碼(若是使用配置文件的話能夠不修改代碼)

若是增長新的同事類,繼承抽象同事類並實現便可,同事類之間無直接引用關係。本實例中,中介者對同事類的引用創建在抽象層,所以在客戶端實例化新增的同事類便可直接使用該對象


模式優缺點

中介者模式優勢:

  1. 簡化對象間的交互。用中介者和同事的一對多交互代替了原來同事之間多對多交互,更利於理解、維護和擴展。
  2. 將各同事解耦。咱們能夠獨立的改變、增長和複用各同事和中介者,符合開閉原則
  3. 減小子類生成。中介者將本來分佈於多個對象的行爲集合在一塊兒,改變這些行爲只需生成新的中介者子類便可,各個同事類可被重用。

中介者模式缺點:

  1. 具體中介者類包含了同事之間的交互細節,可能會致使中介者類很是複雜,難以維護。

模式適用環境

如下狀況可使用中介者模式:

  • 系統對象之間存在複雜的引用關係
  • 一個對象因爲引用了其餘不少對象並直接與其通訊,致使難以複用該對象
  • 想經過一箇中間類來封裝多個類的行爲,而又不想生成太多子類,可使用中介者類,在中介者類中定義對象交互的公共行爲
相關文章
相關標籤/搜索