设计模式系列3--中介者模式

image

我们使用的电脑,你完成的任何一个功能都需要cpu、内存、显卡、键盘、显示器等这些零件相互调用才能完成功能,如果让这些零件之间直接互相调用,那么他们之间的关系可能如下图所示,非常凌乱复杂:

image

但是电脑开发商并没有让这些零件之间相互直接调用,而是通过主板来统一协调,这样每个零件只需要按照主板要求的接口去完成功能即可,然后把处理完成的数据传递给主板就可以了,不需要了解其他零件,此时结构如如下:

image

面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。 在最坏的情况下 ,每一个对象都知道其他所有对象。
虽然将一个系统分割成许多对象通常可以增强可复用性 , 但是对象间相互连接的激增又会 降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作—--系统表现为一个不可分割的整体。而且对系统的行为进行任何较大的改动都十分困难, 因为行为被分布在许多对象中。结果是你可能不得不定义很多子类以定制系统的行为。今天讲解的中介者模式就是为了解决这个问题而诞生的。


定义

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介者模式解决的困境就是多个对象之间的相互引用导致的紧耦合,通过引入一个中介者,原来互相引用的对象都变成同事类,他们之间现在没有任何关系,只和中介者交互,这样就实现了解耦。

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

说白了中介者模式把对象之间的多对多转换成了一对多,从而降低耦合。


UML图及说明

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 1 场景问题# 1.1 如果没有主板## 大家都知道,电脑里面各个配件之间的交互,主要是通过主板来完成的(事实上主...
    七寸知架构阅读 2,157评论 0 56
  • 意图 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改...
    tomas家的小拨浪鼓阅读 1,114评论 0 0
  • 简介用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变...
    Mitchell阅读 447评论 0 0
  • 面向对象设计的五大原则 单一职责原则(SRP) 一个类应该仅有一个职责。 开放封闭原则(OCP) 对扩展开放,...
    LiuHDme阅读 1,447评论 0 3
  • 看到:“量变与质变”这个词汇最先从脑海里跳出来的就是写作了和跑步啦。 对于写作,比如说加入到猫群...
    dou花儿23阅读 80评论 0 0