前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面向对象设计的设计模式(十九):中介者模式

面向对象设计的设计模式(十九):中介者模式

作者头像
用户2932962
发布2019-06-15 15:32:47
4110
发布2019-06-15 15:32:47
举报
文章被收录于专栏:程序员维他命程序员维他命

定义

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

适用场景

系统结构可能会日益变得复杂,对象之间存在大量的相互关联和调用,系统的整体结构容易变为网状结构。在这种情况下,如果需要修改某一个对象,则可能会要跟踪和该对象关联的其他所有对象,并进行处理。耦合越多,修改的地方就会越多。

如果我们使用中介者对象,则可以将系统的网状结构变成以中介者为中心的星型结构。中介者承担了中转作用和协调作用,简化了对象之间的交互,而且还可以给对象间的交互进行进一步的控制。

现在我们清楚了中介者模式的适用场景,下面看一下中介者模式的成员和类图。

成员与类图

成员

中介者模式一共有四个成员:

  1. 抽象中介者(Mediator):抽象中介者定义具体中介者需要实现的接口。
  2. 具体中介者(Concrete Mediator):具体中介者实现抽象中介者定义的接口,承担多个具体同事类之间的中介者的角色。
  3. 抽象同事类(Colleague):抽象同事类定义具体同事类需要实现的接口。
  4. 具体同事类(Concrete Colleague):具体同事类实现抽象同事类定义的接口。

模式类图

状态模式类图

代码示例

场景概述

模拟一个多人对话的场景:当一个人发出消息后,另外的那些人可以收到该消息。

场景分析

假设一共有A,B,C三个人,那么当A发出消息后,需要分别传递给B,C二人。如果三个人直接相互通信,可能伪代码会是这样的:

代码语言:javascript
复制
A sent message to B
A sent message to C

而且随着人数的增多,代码行数也会变多,这显然是不合理的。

因此在这种场景下,我们需要使用中介者模式,在所有人中间来做一个消息的多路转发:当A发出消息后,由中介者来发送给B和C:

代码语言:javascript
复制
A sent message to Mediator ;
Mediator sent message to B & C

下面我们看一下如何用代码来模拟该场景。

代码实现

首先我们创建通话的用户类User:

代码语言:javascript
复制
//================== User.h ==================

@interface User : NSObject

- (instancetype)initWithName:(NSString *)name mediator:(ChatMediator *)mediator;

- (void)sendMessage:(NSString *)message;

- (void)receivedMessage:(NSString *)message;

@end



//================== User.m ==================

@implementation User
{
    NSString *_name;
    ChatMediator *_chatMediator;
}

- (instancetype)initWithName:(NSString *)name mediator:(ChatMediator *)mediator{

    self = [super init];
    if (self) {
        _name = name;
        _chatMediator = mediator;
    }
    return self;
}

- (void)sendMessage:(NSString *)message{

    NSLog(@"================");
    NSLog(@"%@ sent message:%@",_name,message);
    [_chatMediator sendMessage:message fromUser:self];

}

- (void)receivedMessage:(NSString *)message{

    NSLog(@"%@ has received message:%@",_name,message);
}

@end

用户类在初始化的时候需要传入中介者的实例,并持有。目的是为了在后面发送消息的时候把消息转发给中介者。

另外,用户类还对外提供了发送消息和接收消息的接口。而在发送消息的方法内部其实调用的是中介者的发送消息的方法(因为中介者持有了所有用户的实例,因此可以做多路转发),具体是如何做的我们可以看下中介者类ChatMediator的实现:

代码语言:javascript
复制
//================== ChatMediator.h ==================

@interface ChatMediator : NSObject

- (void)addUser:(User *)user;

- (void)sendMessage:(NSString *)message fromUser:(User *)user;

@end



//================== ChatMediator.m ==================

@implementation ChatMediator
{
    NSMutableArray <User *>*_userList;
}

- (instancetype)init{

    self = [super init];

    if (self) {
        _userList = [NSMutableArray array];
    }
    return self;
}

- (void)addUser:(User *)user{

    [_userList addObject:user];
}

- (void)sendMessage:(NSString *)message fromUser:(User *)user{

    [_userList enumerateObjectsUsingBlock:^(User * _Nonnull iterUser, NSUInteger idx, BOOL * _Nonnull stop) {

        if (iterUser != user) {
            [iterUser receivedMessage:message];
        }
    }];
}

@end

中介者类提供了addUser:的方法,因此我们可以不断将用户添加到这个中介者里面(可以看做是注册行为或是“加入群聊”)。在每次加入一个User实例后,都将这个实例添加到中介者持有的这个可变数组里。于是在将来中介者就可以通过遍历数组的方式来做消息的多路转发,具体实现可以看sendMessage:fromUser:这个方法。

到现在为止,用户类和中介者类都创建好了,我们看一下消息是如何转发的:

代码语言:javascript
复制
ChatMediator *cm = [[ChatMediator alloc] init];

User *user1 = [[User alloc] initWithName:@"Jack" mediator:cm];
User *user2 = [[User alloc] initWithName:@"Bruce" mediator:cm];
User *user3 = [[User alloc] initWithName:@"Lucy" mediator:cm];

[cm addUser:user1];
[cm addUser:user2];
[cm addUser:user3];

[user1 sendMessage:@"happy"];
[user2 sendMessage:@"new"];
[user3 sendMessage:@"year"];

从代码中可以看到,我们这里创建了三个用户,分别加入到了聊天中介者对象里。再后面我们分别让每个用户发送了一条消息。我们下面通过日至输出来看一下每个用户的消息接收情况:

代码语言:javascript
复制
[13806:1284059] ================
[13806:1284059] Jack sent message:happy
[13806:1284059] Bruce has received message:happy
[13806:1284059] Lucy has received message:happy
[13806:1284059] ================
[13806:1284059] Bruce sent message:new
[13806:1284059] Jack has received message:new
[13806:1284059] Lucy has received message:new
[13806:1284059] ================
[13806:1284059] Lucy sent message:year
[13806:1284059] Jack has received message:year
[13806:1284059] Bruce has received message:year

下面看一下上面代码对应的类图。

代码对应的类图

中介者模式代码示例类图

优点

  • 中介者使各对象不需要显式地相互引用,从而使其耦合松散。

缺点

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

iOS SDK 和 JDK中的应用

  • JDK中的Timer就是中介者类的实现,而配合使用的TimerTask则是同事类的实现。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员维他命 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 适用场景
  • 成员与类图
    • 成员
      • 模式类图
      • 代码示例
        • 场景概述
          • 场景分析
            • 代码实现
              • 代码对应的类图
              • 优点
              • 缺点
              • iOS SDK 和 JDK中的应用
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档