中介者模式(Mediator Pattern)

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/419 访问。

中介者模式属于行为型模式,它包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散耦合。

当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。

角色:

1、抽象中介者(Mediator):

定义统一的接口用于各同事角色之间的通信,其中主要方法是一个(或多个)事件方法;

2、具体中介者(Concrete Mediator):

实现了抽象中介者所声明的事件方法。具体中介者知晓所有的具体同事类,并负责具体的协调各同事对象的交互关系;

3、抽象同事类(Colleague):

定义出中介者到同事角色的接口。同事角色只知道中介者而不知道其余的同事角色。与其他的同事角色通信的时候,一定要通过中介者角色协作;

4、具体同事类(Concrete Colleague):

所有的具体同事类均从抽象同事类继承而来。实现自己的业务,在需要与其他同事通信的时候,就与持有的中介者通信,中介者会负责与其他的同事交互。

示例:

命名空间MediatorPattern中包含抽象用户类User充当同事基类,它有2个实现类,普通用户GeneralUser类和VIP用户VipUser类,聊天室ChatRoom类充当中介者基类,新浪聊天室SinaChat类为具体中介者。本案例尝试使用中介者模式实现应用最为广泛的网络聊天室。

namespace MediatorPattern
public abstract class User {

    public string Name { get; private set; }

    protected User(string name) {
Name = name;
} public abstract void OnRecieve(User sender, string message, bool group = false); }

抽象用户类User,内部仅维持一个姓名,OnRecieve方法定义在收到其他用户的信息时的回调。此处必须使用public公开OnRecieve方法,因为在聊天室中需要调用它。

C#开发笔记之02-什么时候使用OnXXX方法,这种命名是什么意思?

public class GeneralUser : User {

    public GeneralUser(string name) : base(name) {

    }

    public override void OnRecieve(User sender, string message, bool group = false) {
var groupFlag = group ? "group" : "private";
Console.WriteLine(
$"{this.IdentitySign()} recieved a {groupFlag} message from " +
$"{sender.IdentitySign()},{Environment.NewLine}(s)he says:{message}");
} }

普通用户类GeneralUser,继承自User并实现OnRecieve方法。

public class VipUser : User {

    public VipUser(string name) : base(name) {

    }

    public override void OnRecieve(User sender, string message, bool group = false) {
var groupFlag = group ? "group" : "private";
Console.WriteLine(
$"{this.IdentitySign()} recieved a {groupFlag} message from " +
$"{sender.IdentitySign()},{Environment.NewLine}(s)he says:{message}");
} }

Vip用户类VipUser,继承自User并实现OnRecieve方法。实际开发过程中可不定义2个实现类,使用属性标识是否是Vip用户即可。

public abstract class ChatRoom {

    protected List<User> _users = null;

    protected const string SPLIT_BREAK =
"------------------------------------------------------"; protected ChatRoom() {
_users = new List<User>();
} public void Attach(User user) {
if (user == null) throw new ArgumentNullException();
_users.Add(user);
} public bool Detach(User user) {
if (user == null) throw new ArgumentNullException();
return _users.Remove(user);
} public abstract void Talk2All(User sender, string message);
public abstract void Talk2User(User sender, User reciever, string message); }

聊天室基类ChatRoom,需要维持对User列表的引用并包含添加和删除方法,包含2个主要方法,对所有人说话Talk2All和对某人说话Talk2User。

public class SinaChat : ChatRoom {

    public override void Talk2All(User sender, string message) {
_users.Where(u => u.Name != sender.Name)
.ToList()
.ForEach((u) => u.OnRecieve(sender, message, true));
Console.WriteLine(SPLIT_BREAK);
} public override void Talk2User(User sender, User reciever, string message) {
var user = _users.Where(u => u.Name == reciever.Name)
.FirstOrDefault();
user.OnRecieve(sender, message);
Console.WriteLine(SPLIT_BREAK);
} }

具体聊天室,实现对所有人说话Talk2All和对某人说话Talk2User方法。

public static class Extentions {

    public static string IdentitySign(this User user) {
if (user is VipUser) {
return $"{user.Name}[VIP]";
}
else if (user is GeneralUser) {
return $"{user.Name}";
}
return string.Empty;
} }

定义了一个扩展以方便展示用户Vip标识。

public class Program {

    private static ChatRoom _chatRoom;

    public static void Main(string[] args) {
_chatRoom = new SinaChat(); var juice = new GeneralUser("Juice");
var cola = new GeneralUser("Cola");
var iori = new VipUser("Iori");
var marin = new VipUser("Marin"); _chatRoom.Attach(juice);
_chatRoom.Attach(cola);
_chatRoom.Attach(iori);
_chatRoom.Attach(marin); _chatRoom.Talk2All(juice, "Hello Every one!");
_chatRoom.Talk2User(cola, iori, "Hello Iori!");
_chatRoom.Talk2User(iori, marin, "Hello Marin!"); Console.ReadKey();
} }

以上是调用方的代码演示,以下是这个案例的输出结果:

Cola recieved a group message from Juice,
(s)he says:Hello Every one!
Iori[VIP] recieved a group message from Juice,
(s)he says:Hello Every one!
Marin[VIP] recieved a group message from Juice,
(s)he says:Hello Every one!
------------------------------------------------------
Iori[VIP] recieved a private message from Cola,
(s)he says:Hello Iori!
------------------------------------------------------
Marin[VIP] recieved a private message from Iori[VIP],
(s)he says:Hello Marin!
------------------------------------------------------

优点:

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/419 访问。

1、降低了类的复杂度,将一对多转化成了一对一;

2、各个类之间的解耦,符合迪米特法则。

缺点:

1、中介者角色承担了较多的责任,所以一旦这个中介者对象出现了问题,整个系统将会受到重大的影响。

使用场景:

1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象;

2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

C#设计模式之17-中介者模式的更多相关文章

  1. Java设计模式(17)解释器模式(Interpreter模式)

    Interpreter定义:定义语言的文法,并且建立一个解释器来解释该语言中的句子. Interpreter似乎使用面不是很广,它描述了一个语言解释器是如何构成的,在实际应用中,我们可能很少去构造一个 ...

  2. 【转】设计模式 ( 十五 ) 中介者模式Mediator(对象行为型)

    设计模式 ( 十五 ) 中介者模式Mediator(对象行为型) 1.概述 在面向对象的软件设计与开发过程中,根据"单一职责原则",我们应该尽量将对象细化,使其只负责或呈现单一的职 ...

  3. 设计模式 ( 十五 ) 中介者模式Mediator(对象行为型)

    设计模式 ( 十五 ) 中介者模式Mediator(对象行为型) 1.概述 在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责,即将行为分布到各 ...

  4. Java设计模式学习记录-中介者模式

    前言 中介者模式听名字就能想到也是一种为了解决耦合度的设计模式,其实中介者模式在结构上与观察者.命令模式十分相像:而应用目的又与结构模式“门面模式”有些相似.但区别于命令模式的是大多数中介者角色对于客 ...

  5. [设计模式] 17 中介者模式 Mediator Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对中介者模式是这样说的:用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变 ...

  6. C#设计模式学习笔记:(17)中介者模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7966240.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第五个模式--中 ...

  7. 设计模式学习之中介者模式(Mediator,行为型模式)(18)

    转载地址:http://www.cnblogs.com/zhili/p/MediatorPattern.html 一.引言 在现实生活中,有很多中介者模式的身影,例如QQ游戏平台,聊天室.QQ群和短信 ...

  8. C#设计模式之十七中介者模式(Mediator Pattern)【行为型】

    一.引言 今天我们开始讲“行为型”设计模式的第五个模式,该模式是[中介者模式],英文名称是:Mediator Pattern.还是老套路,先从名字上来看看.“中介者模式”我第一次看到这个名称,我的理解 ...

  9. 17中介者模式Mediator

    一.什么是中介者模式 Mediator模式也叫中介者模式,是由GoF提出的23种 软件设计模式的一种.Mediator模式是行为模式之一, 在Mediator模式中,类之间的交互行为被统一放在 Med ...

  10. 大话设计模式Python实现-中介者模式

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

随机推荐

  1. ES6语法——Promise对象

    一.概念 Promise是异步编程的一种解决方案(解决回调地狱的问题),是一个能够获取异步操作信息的对象.Promise的内部保存着某个未来才会结束的事件(通常是一个异步操作) 二.特点 1.Prom ...

  2. 微信小程序实战:app主页面保存page页面实例

    先上代码. app.js //app.js App({ onLaunch: function () { // 登录 wx.login({ success: res => { if (this.g ...

  3. Inoreader - 在线Rss阅读器

  4. PyQt5事件处理

    事件介绍 事件的处理机制非常的复杂,属于PyQt底层的事,不必我们关心,学会使用就行.如果说事件是用来创建窗口,那么信号与槽就是用来对这个控件进行处理.事件属于低级的处理方式,信号与槽是高级的处理方式 ...

  5. 【mysql】- 索引使用篇

    回顾 每个索引都对应一棵B+树,B+树分为好多层,最下边一层是叶子节点,其余的是内节点.所有用户记录都存储在B+树的叶子节点,所有目录项记录都存储在内节点. InnoDB 存储引擎会自动为主键(如果没 ...

  6. SW算法求全局最小割(Stoer-Wagner算法)

    我找到的唯一能看懂的题解:[ZZ]最小割集Stoer-Wagner算法 似乎是一个冷门算法,连oi-wiki上都没有,不过洛谷上竟然有它的模板题,并且2017百度之星的资格赛还考到了.于是来学习一下. ...

  7. git的分支远程连接和远程分支的拉取推送及冲突处理

    目录 备注: 知识点 Feature分支 多人协作 推送分支 远程分支推送建议 克隆(clone)远程仓库 分支的推送和冲突处理 关联本地分支和远程分支 推送时指定分支或设置分支跟踪 拉取分支时文件冲 ...

  8. Go语言基础语法总结

    1. 认识HelloWorld 在前面的<Go的安装和使用>这篇文章中已经写过HelloWorld.go了,现在就来逐行认识一下它. package main import "f ...

  9. GhostNet: More Features from Cheap Operations

    论文:GhostNet: More Features from Cheap Operations,CVPR 2020 代码:https://github.com/iamhankai/ghostnet. ...

  10. SQLyog无操作一段时间后重新操作会卡死问题(解决办法)

    这种是因为一段时间不操作后,服务器将空闲连接丢弃了,而客户端(sqlyog)不知道,导致长时间无响应,而超时之后,sqlyog 使用了新的连接,所以又可以顺畅操作了. 将会话空闲时间默认改为自定义,填 ...