面向对象设计的设计模式:中介者模式

Posted 程序员大咖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象设计的设计模式:中介者模式相关的知识,希望对你有一定的参考价值。

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇

作者丨维他命君

来源丨程序员维他命(ID:J_Knight_)

定义

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

适用场景

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

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

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

成员与类图

成员

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

  1. 抽象中介者(Mediator):抽象中介者定义具体中介者需要实现的接口。

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

  3. 抽象同事类(Colleague):抽象同事类定义具体同事类需要实现的接口。

  4. 具体同事类(Concrete Colleague):具体同事类实现抽象同事类定义的接口。

模式类图

状态模式类图

代码示例

场景概述

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

场景分析

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

A sent message to B
A sent message to C

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

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

A sent message to Mediator ;
Mediator sent message to B & C

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

代码实现

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

//================== 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的实现:

//================== 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:这个方法。

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

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"];

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

[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则是同事类的实现。

-End-

最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

点击👆卡片,关注后回复【面试题】即可获取

在看点这里好文分享给更多人↓↓

以上是关于面向对象设计的设计模式:中介者模式的主要内容,如果未能解决你的问题,请参考以下文章

c#面向对象10--简单工厂设计模式

面向对象编程思想-中介者模式

javascript设计模式——中介者模式

JAVA SCRIPT设计模式--行为型--设计模式之Mediator中介者模式(17)

中介者模式

设计模式中介者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )