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

西木柚子發表於2016-11-27

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

我們使用的電腦,你完成的任何一個功能都需要cpu、記憶體、顯示卡、鍵盤、顯示器等這些零件相互呼叫才能完成功能,如果讓這些零件之間直接互相呼叫,那麼他們之間的關係可能如下圖所示,非常凌亂複雜:

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

但是電腦開發商並沒有讓這些零件之間相互直接呼叫,而是通過主機板來統一協調,這樣每個零件只需要按照主機板要求的介面去完成功能即可,然後把處理完成的資料傳遞給主機板就可以了,不需要了解其他零件,此時結構如如下:

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

物件導向設計鼓勵將行為分佈到各個物件中。這種分佈可能會導致物件間有許多連線。 在最壞的情況下 ,每一個物件都知道其他所有物件。
雖然將一個系統分割成許多物件通常可以增強可複用性 , 但是物件間相互連線的激增又會 降低其可複用性。大量的相互連線使得一個物件似乎不太可能在沒有其他物件的支援下工作—--系統表現為一個不可分割的整體。而且對系統的行為進行任何較大的改動都十分困難, 因為行為被分佈在許多物件中。結果是你可能不得不定義很多子類以定製系統的行為。今天講解的中介者模式就是為了解決這個問題而誕生的。


定義

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

中介者模式解決的困境就是多個物件之間的相互引用導致的緊耦合,通過引入一箇中介者,原來互相引用的物件都變成同事類,他們之間現在沒有任何關係,只和中介者互動,這樣就實現瞭解耦。

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

說白了中介者模式把物件之間的多對多轉換成了一對多,從而降低耦合。


UML圖及說明

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

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

1、是否需要mediator介面

介面就是用來實現面向介面程式設計,封裝有多箇中介者實現時的帶來的變化。所以如果有多箇中介者,那麼就需要mediator介面,反之則不需要,實際場景中一般很少會有多箇中介者,所以可以不需要介面

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

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

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

因為colleague和mediator需要相互通知自己的變化讓對方做出反應,所以在標準實現中他們之間是相互持有的。其實可以把mediator做成單例,讓同事類直接呼叫就好了。

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

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

在實際開發中,我們不僅要區分是哪個同事類傳遞過來的資訊,還需要區分不同業務型別,所以需要根據實際需求定義多個公共方法。

5、mediator和colleague如何通訊

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


實際場景運用

1、需求分析

假設我們使用電腦播放視訊,把步驟分為如下幾步

  1. 光碟機讀取光碟內容,把讀取到的內容傳遞給主機板
  2. 主機板得到內容,交給cpu處理
  3. cpu處理完畢,把處理後的資料傳遞給主機板
  4. 主機板把資料傳遞給顯示卡,顯示卡顯示視訊(忽略了顯示器顯示這個步驟)

如果不適用中介者模式(加入主機板),那麼每個物件(零件)之間需要互相引用,耦合增加,導致複用修改困難。

3、程式碼實現

定義三個同事類: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類,它們之間互相不知道,減少了耦合。這裡演示的只是這三個類實現的一個功能,實際情況是這三個類存在多種功能,比如播放音訊,看文件。每個功能都需要這三個類之間的相互互動,那麼在任何需要這些功能的地方,都需要引入這三個類,引入的地方越多,這三個類和其他類的耦合度就越高。

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


優缺點

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

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

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

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

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


何時使用

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

  • 一個物件引用其他很多物件並且直接與這些物件通訊,導致難以複用該物件。

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


Demo下載

中介者模式demo

相關文章