設計模式解密(15)- 中介者模式(調停者模式)


1、簡介

別名:調停者模式

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

主要解決:對象與對象之間存在大量的關聯關系,這樣勢必會導致系統的結構變得很復雜,同時若一個對象發生改變,我們也需要跟蹤與之相關聯的對象,同時做出相應的處理。

何時使用:多個類相互耦合,形成了網狀結構。

如何解決:將上述網狀結構分離為星型結構。

核心思想:1、就是將網狀結構處理成星型結構            

        2、將多對多處理成一對多

本質:封裝對象間的交互

英文:Mediator

類型:行為型

PS:附圖示解決的問題

     

2、類圖及組成

(引)類圖:

組成:

  ● 抽象中介者(Mediator)角色:定義統一的接口用於各同事角色之間的通信,其中主要方法是一個(或多個)事件方法。

  ● 具體中介者(ConcreteMediator)角色:實現了抽象中介者所聲明的事件方法。具體中介者知曉所有的具體同事類,並負責具體的協調各同事對象的交互關系。

  ● 抽象同事類(Colleague)角色:定義出中介者到同事角色的接口。同事角色只知道中介者而不知道其余的同事角色。與其他的同事角色通信的時候,一定要通過中介者角色協作。

  ● 具體同事類(ConcreteColleague)角色:所有的具體同事類均從抽象同事類繼承而來。實現自己的業務,在需要與其他同事通信的時候,就與持有的中介者通信,中介者會負責與其他的同事交互。

 

代碼結構:

//抽象中介者類
public interface Mediator {
    /**
     * 同事對象在自身改變的時候來通知中介者的方法
     * 讓中介者去負責相應的與其他同事對象的交互
     */
    public void changed(Colleague c);
}

//抽象同事類
public abstract class Colleague {
    //持有一個中介者對象
    private Mediator mediator;
    /**
     * 構造函數
     */
    public Colleague(Mediator mediator){
        this.mediator = mediator;
    }
    /**
     * 獲取當前同事類對應的中介者對象
     */
    public Mediator getMediator() {
        return mediator;
    }
}

//具體中介者類
public class ConcreteMediator implements Mediator {
    //持有並維護同事A
    private ConcreteColleagueA colleagueA;
    //持有並維護同事B
    private ConcreteColleagueB colleagueB;    

    public void setColleagueA(ConcreteColleagueA colleagueA) {
        this.colleagueA = colleagueA;
    }

    public void setColleagueB(ConcreteColleagueB colleagueB) {
        this.colleagueB = colleagueB;
    }

    @Override
    public void changed(Colleague c) {
        /**
         * 某一個同事類發生了變化,通常需要與其他同事交互
         * 具體協調相應的同事對象來實現協作行為
         */
    }
}

//具體同事類
public class ConcreteColleagueA extends Colleague {

    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
    }
    /**
     * 示意方法,執行某些操作
     */
    public void operation(){
        //在需要跟其他同事通信的時候,通知中介者對象
        getMediator().changed(this);
    }
}
public class ConcreteColleagueB extends Colleague {

    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
    }
    /**
     * 示意方法,執行某些操作
     */
    public void operation(){
        //在需要跟其他同事通信的時候,通知中介者對象
        getMediator().changed(this);
    }
}

3、實例引入

假設現在有A、B、C建立了一個微信討論組,他們有什么問題就在這里討論,A在猶豫今天中午吃什么,A同學只要在討論組里問一聲就可以了,不必要直接去和B、C同學打交道,省去了很多麻煩事。怎么實現呢?

抽象中介者:

package com.designpattern.Mediator;

/**
 * 抽象中介者類
 * @author Json<<json1990@foxmail.com>>
 */
public interface Mediator {
    /**
     * 發送消息
     */
    public void chat(People p,String message);
}

抽象同事類:

package com.designpattern.Mediator;

/**
 * 抽象同事類  -- 聊天人員
 * @author Json<<json1990@foxmail.com>>
 */
public abstract class People { 
    //人員昵稱
    private String name;
    //持有一個中介者對象
    private Mediator mediator;
    
    /**
     * 構造函數
     */
    public People(Mediator mediator,String name){
        this.mediator = mediator;
        this.name = name;
    }
    /**
     * 獲取中介者對象
     */
    public Mediator getMediator() {
        return mediator;
    }
    /**
     * 獲取昵稱
     */
    public String getName() {
        return name;
    }
    
    /**
     * 接收消息
     */
    public abstract void receive(String message);
    
    /**
     * 發送消息
     */
    public abstract void send(String message);
}

3個具體同事類:

package com.designpattern.Mediator;

/**
 * 具體同事類  -- 人員a
 * @author Json<<json1990@foxmail.com>>
 */
public class PeopleA extends People {

    public PeopleA(Mediator mediator,String name) {
        super(mediator, name);
    }
    
    /**
     * 接收消息
     */
    public void receive(String message){
        System.out.println("【A】收到消息:【"+message+"】");
    }
    
    /**
     * 發送消息
     */
    public void send(String message){
        System.out.println("【A】發出消息:【"+message+"】");
    }
}
package com.designpattern.Mediator;

/**
 * 具體同事類  -- 人員b
 * @author Json<<json1990@foxmail.com>>
 */
public class PeopleB extends People {

    public PeopleB(Mediator mediator,String name) {
        super(mediator, name);
    }
    
    /**
     * 接收消息
     */
    public void receive(String message){
        System.out.println("【B】收到消息:【"+message+"】");
    }
    
    /**
     * 發送消息
     */
    public void send(String message){
        System.out.println("【B】發出消息:【"+message+"】");
    }
}
package com.designpattern.Mediator;

/**
 * 具體同事類  -- 人員c
 * @author Json<<json1990@foxmail.com>>
 */
public class PeopleC extends People {

    public PeopleC(Mediator mediator,String name) {
        super(mediator, name);
    }
    
    /**
     * 接收消息
     */
    public void receive(String message){
        System.out.println("【C】收到消息:【"+message+"】");
    }
    
    /**
     * 發送消息
     */
    public void send(String message){
        System.out.println("【C】發出消息:【"+message+"】");
    }
}

具體中介者實現:

package com.designpattern.Mediator;

/**
 * 具體中介者類
 * @author Json<<json1990@foxmail.com>>
 */
public class MessageMediator implements Mediator {
    //持有並維護人員A
    private PeopleA A;
    //持有並維護人員B
    private PeopleB B;    
    //持有並維護人員C
    private PeopleC C;    

    public void setPeopleA(PeopleA A) {
        this.A = A;
    }

    public void setPeopleB(PeopleB B) {
        this.B = B;
    }
    
    public void setPeopleC(PeopleC C) {
        this.C = C;
    }

    /**
     * 發送消息
     */
    @Override
    public void chat(People p,String message) {
        if (p instanceof PeopleA) {
            A.send(message);
            B.receive(message);
            C.receive(message); 
        } else if (p instanceof PeopleB) {
            B.send(message);
            A.receive(message);
            C.receive(message);
        } else if (p instanceof PeopleC) {
            C.send(message);
            A.receive(message);
            B.receive(message);
        } 
    }
}

測試:

package com.designpattern.Mediator;

/**
 * 測試
 * @author Json<<json1990@foxmail.com>>
 */
public class Client {

    public static void main(String[] args) {
        MessageMediator mediator = new MessageMediator();
        
        PeopleA a = new PeopleA(mediator,"A");
        PeopleB b = new PeopleB(mediator,"B");
        PeopleC c = new PeopleC(mediator,"C");
        
        mediator.setPeopleA(a);
        mediator.setPeopleB(b);
        mediator.setPeopleC(c);
        
        mediator.chat(a, "中午吃啥飯?");
        System.out.println();
        
        mediator.chat(b,"我想吃刀削面");
        System.out.println();

        mediator.chat(c,"我也想吃刀削面");
        System.out.println();
        
        mediator.chat(a, "行,那中午一起去吃刀削面吧");
        System.out.println();
    }
}

結果:

【A】發出消息:【中午吃啥飯?】
【B】收到消息:【中午吃啥飯?】
【C】收到消息:【中午吃啥飯?】

【B】發出消息:【我想吃刀削面】
【A】收到消息:【我想吃刀削面】
【C】收到消息:【我想吃刀削面】

【C】發出消息:【我也想吃刀削面】
【A】收到消息:【我也想吃刀削面】
【B】收到消息:【我也想吃刀削面】

【A】發出消息:【行,那中午一起去吃刀削面吧】
【B】收到消息:【行,那中午一起去吃刀削面吧】
【C】收到消息:【行,那中午一起去吃刀削面吧】

4、優缺點

優點:

   簡化了對象之間的交互:它用中介者和同事的一對多交互代替了原來同事之間的多對多交互,一對多關系更容易理解、維護和擴展,將原本難以理解的網狀結構轉換成相對簡單的星型結構。

  各同事對象之間解耦:中介者有利於各同事之間的松耦合,我們可以獨立的改變和復用每一個同事和中介者,增加新的中介者和新的同事類都比較方便,更好地符合“開閉原則”。

  減少子類生成:中介者將原本分布於多個對象間的行為集中在一起,改變這些行為只需生成新的中介者子類即可,這使各個同事類可被重用,無須對同事類進行擴展。

缺點:

  中介者會龐大,變得復雜難以維護。

5、使用場景

  1、對象間的交互雖定義明確然而非常復雜,導致一組對象彼此相互依賴而且難以理解。

  2、因為對象引用了許多其他對象並與其通信,導致對象難以復用。

  3、想要定制一個分布在多個類中的邏輯或者行為,又不想生成太多子類。

  實際應用

    Mediator模式在事件驅動類應用中比較多,例如聊天、消息傳遞等等,需要有一個MessageMediator,專門負責request/reponse之間任務的調節。

    MVC模式中,Controller是一種Mediator。

    JDK的具體應用:

        java.util.Timer

        java.util.concurrent.Executor#execute()

        java.util.concurrent.ExecutorService#submit()

        java.lang.reflect.Method#invoke()

    .......

6、中介者模式和外觀模式

  1、外觀模式是結構型模式,中介者模式是行為型模式;

  2、中介者模式主要用來封裝多個平等對象之間相互的交互,多用在系統內部的多個模塊之間;

     外觀模式旨在提供一個高層次的接口,封裝的是單向的交互,是從客戶端訪問系統的調用,沒有從系統中來訪問客戶端的調用;

     外觀模式協議是單向,中介者模式協議是雙向;

  3、中介者模式的實現里面,是需要實現具體的交互功能的;而外觀模式的實現里面,一般是組合調用或是轉調內部實現的功能,通常外觀模式不添加額外的功能;

  4、中介者模式的目的主要是松散多個模塊之間的耦合,把這些耦合關系全部放到中介者中去實現;而外觀模式的目的是簡化客戶端的調用;

7、總結

  中介者模式很容易在系統中應用,也很容易在系統中誤用。當系統出現了“多對多”交互復雜的對象群,不要急於使用中介者模式,而先要思考在設計上是不是合理↓↓↓

  PS:不應當在職責混亂的時候使用;

 

PS:源碼地址   https://github.com/JsonShare/DesignPattern/tree/master 

   

PS:原文地址 http://www.cnblogs.com/JsonShare/p/7263876.html

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM