設計模式系列3--中介者模式

image

咱們使用的電腦,你完成的任何一個功能都須要cpu、內存、顯卡、鍵盤、顯示器等這些零件相互調用才能完成功能,若是讓這些零件之間直接互相調用,那麼他們之間的關係可能以下圖所示,很是凌亂複雜:javascript

image

可是電腦開發商並無讓這些零件之間相互直接調用,而是經過主板來統一協調,這樣每一個零件只須要按照主板要求的接口去完成功能便可,而後把處理完成的數據傳遞給主板就能夠了,不須要了解其餘零件,此時結構如以下:java

image

面向對象設計鼓勵將行爲分佈到各個對象中。這種分佈可能會致使對象間有許多鏈接。 在最壞的狀況下 ,每個對象都知道其餘全部對象。
雖然將一個系統分割成許多對象一般能夠加強可複用性 , 可是對象間相互鏈接的激增又會 下降其可複用性。大量的相互鏈接使得一個對象彷佛不太可能在沒有其餘對象的支持下工做—--系統表現爲一個不可分割的總體。並且對系統的行爲進行任何較大的改動都十分困難, 由於行爲被分佈在許多對象中。結果是你可能不得不定義不少子類以定製系統的行爲。今天講解的中介者模式就是爲了解決這個問題而誕生的。編程


定義

用一箇中介對象來封裝一系列的對象交互。中介者使各對象不須要顯式地相互引用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互。app

中介者模式解決的困境就是多個對象之間的相互引用致使的緊耦合,經過引入一箇中介者,原來互相引用的對象都變成同事類,他們之間如今沒有任何關係,只和中介者交互,這樣就實現瞭解耦。ide

這樣之後若是增長或者修改任何同事類的功能,也只須要修改中介者,不須要修改其餘同事類。spa

說白了中介者模式把對象之間的多對多轉換成了一對多,從而下降耦合。設計


UML圖及說明

image

上圖是標準的中介者模式,其實在實際使用的時候會作必定程度的變形使用。下面加以說明:3d

一、是否須要mediator接口

接口就是用來實現面向接口編程,封裝有多箇中介者實現時的帶來的變化。因此若是有多箇中介者,那麼就須要mediator接口,反之則不須要,實際場景中通常不多會有多箇中介者,因此能夠不須要接口code

二、是否須要定義同事類的父類

其實在實際開發中,這些同事類不可能抽象爲同一個父類,他們之間不多有共同性。因此不必給他們定義一個共同父類cdn

三、colleague和mediator是否須要相互持有

由於colleague和mediator須要相互通知本身的變化讓對方作出反應,因此在標準實現中他們之間是相互持有的。其實能夠把mediator作成單例,讓同事類直接調用就行了。

一樣的道理,mediator也不必持有colleague,能夠經過方法的參數吧colleague傳遞到mediator。

四、mediator只須要提供一個公共方法嗎

在實際開發中,咱們不只要區分是哪一個同事類傳遞過來的信息,還須要區分不一樣業務類型,因此須要根據實際需求定義多個公共方法。

五、mediator和colleague如何通訊

標準模式裏面是互相引用,而後告知對方,其實還可使用觀察者模式,讓二者之間互相觀察,有了變化就能夠通知對方


實際場景運用

一、需求分析

假設咱們使用電腦播放視頻,把步驟分爲以下幾步

  1. 光驅讀取光盤內容,把讀取到的內容傳遞給主板
  2. 主板獲得內容,交給cpu處理
  3. cpu處理完畢,把處理後的數據傳遞給主板
  4. 主板把數據傳遞給顯卡,顯卡顯示視頻(忽略了顯示器顯示這個步驟)

若是不適用中介者模式(加入主板),那麼每一個對象(零件)之間須要互相引用,耦合增長,致使複用修改困難。

三、代碼實現

定義三個同事類:cpu、CDDriver、videoCard

#import <Foundation/Foundation.h>

@interface CPU : NSObject
-(void)executeData:(NSMutableString *)data;
@end


======
#import "CPU.h"
#import "mainBoard.h"

@implementation CPU
-(void )executeData:(NSMutableString *)data{
    [data appendString:@"+通過cpu處理"];
    [[mainBoard shareInstance] handleData:data dataSource:self];
}
@end複製代碼
#import "CDDriver.h"
#import "mainBoard.h"

@implementation CDDriver
-(void)readCD{
    NSString *data = @"BBC地球探索之旅";
    NSMutableString *mStr = [[NSMutableString alloc]initWithString:data];
    [[mainBoard shareInstance] handleData:mStr dataSource:self];
}
@end複製代碼
#import "VideoCard.h"

@implementation VideoCard

-(void )executeData:(NSMutableString *)data{
    [data appendString:@"+通過顯卡處理"];
    NSLog(@"開始播放視頻:「%@",data);
}

@end複製代碼

定義mediator類

#import <Foundation/Foundation.h>

@interface mainBoard : NSObject
+(instancetype)shareInstance;

-(void)handleData:(NSMutableString *)data dataSource:(id)source;
@end


=======================

#import "mainBoard.h"
#import "CPU.h"
#import "CDDriver.h"
#import "VideoCard.h"

static mainBoard *instance = nil;

@implementation mainBoard
+(instancetype)shareInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if(instance == nil){
            instance = [[self alloc]init];
        }
    });

    return instance;
}

-(void)handleData:(NSMutableString *)data dataSource:(id)source{
    if  ([source isKindOfClass:[CDDriver class]]){
        CPU *cpu = [CPU new];
        [cpu executeData:data];
    }else if ([source isKindOfClass:[CPU class]]){
        VideoCard *video = [VideoCard new];
        [video executeData:data];

    }
}

@end複製代碼

客戶端調用:

#import <Foundation/Foundation.h>
#import "CDDriver.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        CDDriver *cd = [CDDriver new];
        [cd  readCD];

    }
    return 0;
}複製代碼

經過上面的例子能夠看到三個同事類的交互對象只有mainboard這個mediator類,它們之間互相不知道,減小了耦合。這裏演示的只是這三個類實現的一個功能,實際狀況是這三個類存在多種功能,好比播放音頻,看文檔。每一個功能都須要這三個類之間的相互交互,那麼在任何須要這些功能的地方,都須要引入這三個類,引入的地方越多,這三個類和其餘類的耦合度就越高。

假設這三個類須要更改,那麼牽一髮動全身,其餘全部引用這些類的地方都要改,可是若是引入中介者模式,則不會有這些問題。


優缺點

一、 減小了子類生成Mediator將本來分佈於多個對象間的行爲集中在一塊兒 。 改 變 這 些 行 爲,只需生成 Meditor的子類便可。這樣各個 Colleage 類可被重用。

二、 它將各 Colleague 解耦 Mediator 有利於各 Coleague 間的鬆耦合 . 你 可 以 獨 立 的 改 變 和 復
用各 Colleague 類和 Mediator 類。

三、它 簡 化 了 對 象 協 議 用 Mediator 和各 Colleague 間 的 一 對 多 的 交 互 來 代 替 多 對 多 的 交 互 。一對多的關係更易於理解、維護和擴展。

四、它對對象如何協做進行了抽象 將中介做爲一個獨立的概念並將其封裝在一個對象中,
使你將注意力從對象各自自己的行爲轉移到它們之間的交互上來。這有助於弄清楚一個系統 中的對象是如何交互的。

五、它使控制集中化。中介者模式將交互的複雜性變爲中介者的複雜性。由於中介者封裝了協議 , 它可能變得比任一個colleague都複雜。 這可能使得中介者自身成爲一個難於維護的龐然大物。


什麼時候使用

  • 一組對象以定義良好可是複雜的方式進行通訊。產生的相互依賴關係結構混亂且難以理解。

  • 一個對象引用其餘不少對象而且直接與這些對象通訊,致使難以複用該對象。

  • 想定製一個分佈在多個類中的行爲,而又不想生成太多的子類。


Demo下載

中介者模式demo

相關文章
相關標籤/搜索