設(shè)計模式系列3--中介者模式

image

我們使用的電腦,你完成的任何一個功能都需要cpu、內(nèi)存、顯卡、鍵盤、顯示器等這些零件相互調(diào)用才能完成功能,如果讓這些零件之間直接互相調(diào)用,那么他們之間的關(guān)系可能如下圖所示,非常凌亂復(fù)雜:

image

但是電腦開發(fā)商并沒有讓這些零件之間相互直接調(diào)用,而是通過主板來統(tǒng)一協(xié)調(diào),這樣每個零件只需要按照主板要求的接口去完成功能即可,然后把處理完成的數(shù)據(jù)傳遞給主板就可以了,不需要了解其他零件,此時結(jié)構(gòu)如如下:

image

面向?qū)ο笤O(shè)計鼓勵將行為分布到各個對象中。這種分布可能會導(dǎo)致對象間有許多連接。 在最壞的情況下 ,每一個對象都知道其他所有對象。
雖然將一個系統(tǒng)分割成許多對象通??梢栽鰪娍蓮?fù)用性 , 但是對象間相互連接的激增又會 降低其可復(fù)用性。大量的相互連接使得一個對象似乎不太可能在沒有其他對象的支持下工作—--系統(tǒng)表現(xiàn)為一個不可分割的整體。而且對系統(tǒng)的行為進行任何較大的改動都十分困難, 因為行為被分布在許多對象中。結(jié)果是你可能不得不定義很多子類以定制系統(tǒng)的行為。今天講解的中介者模式就是為了解決這個問題而誕生的。


定義

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

中介者模式解決的困境就是多個對象之間的相互引用導(dǎo)致的緊耦合,通過引入一個中介者,原來互相引用的對象都變成同事類,他們之間現(xiàn)在沒有任何關(guān)系,只和中介者交互,這樣就實現(xiàn)了解耦。

這樣以后如果增加或者修改任何同事類的功能,也只需要修改中介者,不需要修改其他同事類。

說白了中介者模式把對象之間的多對多轉(zhuǎn)換成了一對多,從而降低耦合。


UML圖及說明

image

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

1、是否需要mediator接口

接口就是用來實現(xiàn)面向接口編程,封裝有多個中介者實現(xiàn)時的帶來的變化。所以如果有多個中介者,那么就需要mediator接口,反之則不需要,實際場景中一般很少會有多個中介者,所以可以不需要接口

2、是否需要定義同事類的父類

其實在實際開發(fā)中,這些同事類不可能抽象為同一個父類,他們之間很少有共同性。所以沒必要給他們定義一個共同父類

3、colleague和mediator是否需要相互持有

因為colleague和mediator需要相互通知自己的變化讓對方做出反應(yīng),所以在標準實現(xiàn)中他們之間是相互持有的。其實可以把mediator做成單例,讓同事類直接調(diào)用就好了。

同樣的道理,mediator也沒必要持有colleague,可以通過方法的參數(shù)吧colleague傳遞到mediator。

4、mediator只需要提供一個公共方法嗎

在實際開發(fā)中,我們不僅要區(qū)分是哪個同事類傳遞過來的信息,還需要區(qū)分不同業(yè)務(wù)類型,所以需要根據(jù)實際需求定義多個公共方法。

5、mediator和colleague如何通信

標準模式里面是互相引用,然后告知對方,其實還可以使用觀察者模式,讓兩者之間互相觀察,有了變化就可以通知對方


實際場景運用

1、需求分析

假設(shè)我們使用電腦播放視頻,把步驟分為如下幾步

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

如果不適用中介者模式(加入主板),那么每個對象(零件)之間需要互相引用,耦合增加,導(dǎo)致復(fù)用修改困難。

3、代碼實現(xiàn)

定義三個同事類: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:@"+經(jīng)過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:@"+經(jīng)過顯卡處理"];
    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

客戶端調(diào)用:



#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類,它們之間互相不知道,減少了耦合。這里演示的只是這三個類實現(xiàn)的一個功能,實際情況是這三個類存在多種功能,比如播放音頻,看文檔。每個功能都需要這三個類之間的相互交互,那么在任何需要這些功能的地方,都需要引入這三個類,引入的地方越多,這三個類和其他類的耦合度就越高。

假設(shè)這三個類需要更改,那么牽一發(fā)動全身,其他所有引用這些類的地方都要改,但是如果引入中介者模式,則不會有這些問題。


優(yōu)缺點

1、 減少了子類生成Mediator將原本分布于多個對象間的行為集中在一起 。 改 變 這 些 行 為,只需生成 Meditor的子類即可。這樣各個 Colleage 類可被重用。

2、 它將各 Colleague 解耦 Mediator 有利于各 Coleague 間的松耦合 . 你 可 以 獨 立 的 改 變 和 復(fù)
用各 Colleague 類和 Mediator 類。

3、它 簡 化 了 對 象 協(xié) 議 用 Mediator 和各 Colleague 間 的 一 對 多 的 交 互 來 代 替 多 對 多 的 交 互 。一對多的關(guān)系更易于理解、維護和擴展。

4、它對對象如何協(xié)作進行了抽象 將中介作為一個獨立的概念并將其封裝在一個對象中,
使你將注意力從對象各自本身的行為轉(zhuǎn)移到它們之間的交互上來。這有助于弄清楚一個系統(tǒng) 中的對象是如何交互的。

5、它使控制集中化。中介者模式將交互的復(fù)雜性變?yōu)橹薪檎叩膹?fù)雜性。因為中介者封裝了協(xié)議 , 它可能變得比任一個colleague都復(fù)雜。 這可能使得中介者自身成為一個難于維護的龐然大物。


何時使用

  • 一組對象以定義良好但是復(fù)雜的方式進行通信。產(chǎn)生的相互依賴關(guān)系結(jié)構(gòu)混亂且難以理解。

  • 一個對象引用其他很多對象并且直接與這些對象通信,導(dǎo)致難以復(fù)用該對象。

  • 想定制一個分布在多個類中的行為,而又不想生成太多的子類。


Demo下載

中介者模式demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容