1

看图识模式

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

clipboard.png

模式动机

这样设计将导致系统出现以下问题

  1. 系统结构复杂:对象之间存在大量的相互关联和调用,若有一个对象发生变化,则需要跟踪和该对象关联的其他所有对象,并进行适当处理

  2. 对象可重用性差:由于一个对象和其他对象具有很强的关联,若没有其他对象的支持,一个对象很难被另一个系统或模块重用,这些对象表现出来更像一个不可分割的整体,职责较为混乱。

  3. 系统扩展性低:增加一个新的对象需要在原有相关对象上增加引用,增加新的引用关系也需要调整原有对象,系统耦合度很高,对象操作很不灵活,扩展性差

在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责。对于一个模块,可能由很多对象构成,而且这些对象之间可能存在相互的引用,为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们需要使用中介者模式,这就是中介者模式的模式动机。

解决

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

clipboard.png

在这里主板扮演了中介者的角色。它把之前每个模块之间的相互引用关系统一到了自己里面,其它模块之间相互而复杂的引用关系消失了,取而代之的是每个模块只需要和主板建立关联关系即可。

模式定义

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

结构图

静态结构类图

clipboard.png

  • Mediator: 抽象中介者

  • ConcreteMediator: 具体中介者

  • Colleague: 抽象同事类

  • ConcreteColleague: 具体同事类

应用示例

这里简单的使用上面电脑主板和各组件的关系为例演示

Mediator抽象中介者类

// 抽象的mediator类

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

@interface MainBoard : NSObject

- (void)registerComponent:(AbsComponent *)component;
- (void)operationMsg:(NSString *)msg component:(AbsComponent *)component;

@end

#import "MainBoard.h"

@implementation MainBoard

- (void)registerComponent:(AbsComponent *)component
{
    // 抽象类空实现就行了。。。。
}

- (void)operationMsg:(NSString *)msg component:(AbsComponent *)component;
{
    // 抽象类空实现就行了。。。。
}

@end

ConcreteMediator具体中介者类

这里我们把AsusMainBoard(华硕主板)作为一个具体的实现类,以后可以拓展其他的主板(主板厂商可以有很多)

// 华硕主板,这是一个concreteMediator

#import "MainBoard.h"

@interface AsusMainBoard : MainBoard

@end

#import "AsusMainBoard.h"
#import "CPUComponent.h"
#import "VGAComponent.h"

@interface AsusMainBoard ()

@property (nonatomic, strong) CPUComponent *cpu;
@property (nonatomic, strong) VGAComponent *vga;

@end

@implementation AsusMainBoard

- (void)registerComponent:(AbsComponent *)component
{
    if ([component isKindOfClass:[CPUComponent class]]) {
        self.cpu = (CPUComponent *)component;
        component.mainboard = self;
    } else if ([component isKindOfClass:[VGAComponent class]]) {
        self.vga = (VGAComponent *)component;
        component.mainboard = self;
    }
}

- (void)operationMsg:(NSString *)msg component:(AbsComponent *)component;
{
    if ([component isKindOfClass:[CPUComponent class]]) {
        [self.vga receiveMsg:msg];
    }
    // else if...
}

@end

Colleague抽象同事类

// 抽象的colleague类

#import <Foundation/Foundation.h>
@class MainBoard;

@interface AbsComponent : NSObject

@property (nonatomic, weak) MainBoard *mainboard;

- (void)sendMsg:(NSString *)data;
- (void)receiveMsg:(NSString *)data;

@end

#import "AbsComponent.h"

@implementation AbsComponent

- (void)sendMsg:(NSString *)data
{
    // 抽象类空实现就行了。。。。
}

- (void)receiveMsg:(NSString *)data
{
    // 抽象类空实现就行了。。。。
}

@end

ConcreteColleague具体同事类

这里有2个具体组件: CPUComponent(CPU)、VGAComponent(显卡)

CPUComponent类

#import "AbsComponent.h"

@interface CPUComponent : AbsComponent

@end

#import "CPUComponent.h"
#import "AsusMainBoard.h"

@implementation CPUComponent

- (void)sendMsg:(NSString *)data
{
    // .....处理完
    [self.mainboard operationMsg:data component:self];
}

- (void)receiveMsg:(NSString *)data
{
    NSLog(@"cpu接受到数据: %@", data);
    // ...... 处理中
    NSLog(@"cpu计算数据完成");
}

@end

VGAComponent类

// 显卡组件,这是一个concreteColleague

#import "AbsComponent.h"

@interface VGAComponent : AbsComponent

@end

#import "VGAComponent.h"
#import "AsusMainBoard.h"

@implementation VGAComponent

- (void)sendMsg:(NSString *)data
{
    // .....处理完
    [self.mainboard operationMsg:data component:self];
}

- (void)receiveMsg:(NSString *)data
{
    NSLog(@"显卡接受到数据: %@", data);
    // ...... 处理中
    NSLog(@"显卡显示数据成功");
}
@end

最后看一下客户端调用

#import "CPUComponent.h"
#import "VGAComponent.h"
#import "AsusMainBoard.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        CPUComponent *cpu = [CPUComponent new];
        VGAComponent *vga = [VGAComponent new];
        
        AsusMainBoard *asus = [AsusMainBoard new];
        [asus registerComponent:cpu];
        [asus registerComponent:vga];
        
        [cpu sendMsg:@"《历史的天空》(电影)"];
    }
    return 0;
}

运行结果:

clipboard.png

模式应用

MVC架构中控制器

Controller 作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互。如在Struts中,Action就可以作为JSP页面与业务对象之间的中介者。

模式拓展

中介者模式与迪米特法则

  • 在中介者模式中,通过创造出一个中介者对象,将系统中有关的对象所引用的其他对象数目减少到最少,使得一个对象与其同事之间的相互作用被这个对象与中介者对象之间的相互作用所取代。因此,中介者模式就是迪米特法则的一个典型应用。

中介者模式与GUI开发

  • 中介者模式可以方便地应用于图形界面(GUI)开发中,在比较复杂的界面中可能存在多个界面组件之间的交互关系。

  • 对于这些复杂的交互关系,有时候我们可以引入一个中介者类,将这些交互的组件作为具体的同事类,将它们之间的引用和控制关系交由中介者负责,在一定程度上简化系统的交互,这也是中介者模式的常见应用之一。

优点&缺点

优点

  • Mediator将原本分布于多个对象间的行为集中在一起 。改变这些行为,只需生成 Meditor的子类即可。这样各个Colleage 类可被重用。

  • 可以简化各同事类的设计和实现

  • 将各同事解耦

  • 简化了对象之间的交互

缺点

  • 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。


danielmea
28 声望8 粉丝

程序猿的逗比日常-------