中介者模式(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. GPO - Disabling Task Manager Access

    Create a GPO to disable Task Manager Access to normal users. Add an exception to Domain Admins.

  2. Python Ethical Hacking - TROJANS Analysis(4)

    Adding Icons to Generated Executables Prepare a proper icon file. https://www.iconfinder.com/ Conver ...

  3. 高效C++:资源管理

    C++中资源泄漏一直都是老大难的问题,特别是在嵌入式环境中,一点点的资源泄漏,加上长时间的运行们就会导致程序崩溃,这种问题定位非常困难,无规律偶发.解决问题的一种方式是使用特定工具检查内存泄漏,优点是 ...

  4. 文件传输协议---TFTP

    简介 TFTP协议全称为简单文件传输协议,是以UDP为基础的应用层协议,主要用于不同设备之间的文件传输.具有协议简单,易于实现的特点,常用于嵌入式设备开发中. 传输模式 数据的存储有不同的格式,磁盘中 ...

  5. three.js 数学方法之Plane

    今天郭先生就来继续说一说three.js数学方法中的plane(平面).在三维空间中无限延伸的二维平面,平面方程用单位长度的法向量和常数表示.构造器为Plane( normal : Vector3, ...

  6. DP学习记录Ⅱ

    DP学习记录Ⅰ 以下为 DP 的优化. 人脑优化DP P5664 Emiya 家今天的饭 正难则反.考虑计算不合法方案.一个方案不合法一定存在一个主食,使得该主食在多于一半的方法中出现. 枚举这个&q ...

  7. SpringBoot多数据库连接(mysql+oracle)

    出于业务需求,有时我们需要在spring boot web应用程序中配置多个数据源并连接到多个数据库. 使用过Spring Boot框架的小伙伴们,想必都发现了Spring Boot对JPA提供了非常 ...

  8. CSS样式基础2

    CSS: 一.常用样式:字体,颜色,背景 二.布局:浮动  定位  标签特性 三.标签盒子模型: 边距  边框 四.动画:旋转 渐变 注意:子标签会继承父标签的样式但不是所有的样式都会被继承. 1.1 ...

  9. react 阻止事件传递/冒泡

    当我们设计界面时,在以下情况会需要阻止元素/组件内的事件阻断,不被上层触发: 弹出提示框,期望点击框外空白区域可以关闭弹框.点击框内不关闭弹框 组件设计时,期望点击全局/点击指定元素时,显示不一样的交 ...

  10. jmeter单接口和多接口测试

    @@@@@@@@@@@@@@@ # 路漫漫其修远 最近接触到了多接口串联,接口串联的技术会在其他帖子有说明,其核心技术点就是通过正则表达式和变量来实现接口的关联.目前为止呢笔者用到的地方还只有一个,就 ...