C#设计模式之17-中介者模式
中介者模式(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-中介者模式的更多相关文章
- Java设计模式(17)解释器模式(Interpreter模式)
Interpreter定义:定义语言的文法,并且建立一个解释器来解释该语言中的句子. Interpreter似乎使用面不是很广,它描述了一个语言解释器是如何构成的,在实际应用中,我们可能很少去构造一个 ...
- 【转】设计模式 ( 十五 ) 中介者模式Mediator(对象行为型)
设计模式 ( 十五 ) 中介者模式Mediator(对象行为型) 1.概述 在面向对象的软件设计与开发过程中,根据"单一职责原则",我们应该尽量将对象细化,使其只负责或呈现单一的职 ...
- 设计模式 ( 十五 ) 中介者模式Mediator(对象行为型)
设计模式 ( 十五 ) 中介者模式Mediator(对象行为型) 1.概述 在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责,即将行为分布到各 ...
- Java设计模式学习记录-中介者模式
前言 中介者模式听名字就能想到也是一种为了解决耦合度的设计模式,其实中介者模式在结构上与观察者.命令模式十分相像:而应用目的又与结构模式“门面模式”有些相似.但区别于命令模式的是大多数中介者角色对于客 ...
- [设计模式] 17 中介者模式 Mediator Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对中介者模式是这样说的:用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变 ...
- C#设计模式学习笔记:(17)中介者模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7966240.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第五个模式--中 ...
- 设计模式学习之中介者模式(Mediator,行为型模式)(18)
转载地址:http://www.cnblogs.com/zhili/p/MediatorPattern.html 一.引言 在现实生活中,有很多中介者模式的身影,例如QQ游戏平台,聊天室.QQ群和短信 ...
- C#设计模式之十七中介者模式(Mediator Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第五个模式,该模式是[中介者模式],英文名称是:Mediator Pattern.还是老套路,先从名字上来看看.“中介者模式”我第一次看到这个名称,我的理解 ...
- 17中介者模式Mediator
一.什么是中介者模式 Mediator模式也叫中介者模式,是由GoF提出的23种 软件设计模式的一种.Mediator模式是行为模式之一, 在Mediator模式中,类之间的交互行为被统一放在 Med ...
- 大话设计模式Python实现-中介者模式
中介者模式(Mediator Pattern):用一个对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使耦合松散,而且可以独立地改变它们之间的交互. 下面是一个中介者模式的demo ...
随机推荐
- GPO - Disabling Task Manager Access
Create a GPO to disable Task Manager Access to normal users. Add an exception to Domain Admins.
- Python Ethical Hacking - TROJANS Analysis(4)
Adding Icons to Generated Executables Prepare a proper icon file. https://www.iconfinder.com/ Conver ...
- 高效C++:资源管理
C++中资源泄漏一直都是老大难的问题,特别是在嵌入式环境中,一点点的资源泄漏,加上长时间的运行们就会导致程序崩溃,这种问题定位非常困难,无规律偶发.解决问题的一种方式是使用特定工具检查内存泄漏,优点是 ...
- 文件传输协议---TFTP
简介 TFTP协议全称为简单文件传输协议,是以UDP为基础的应用层协议,主要用于不同设备之间的文件传输.具有协议简单,易于实现的特点,常用于嵌入式设备开发中. 传输模式 数据的存储有不同的格式,磁盘中 ...
- three.js 数学方法之Plane
今天郭先生就来继续说一说three.js数学方法中的plane(平面).在三维空间中无限延伸的二维平面,平面方程用单位长度的法向量和常数表示.构造器为Plane( normal : Vector3, ...
- DP学习记录Ⅱ
DP学习记录Ⅰ 以下为 DP 的优化. 人脑优化DP P5664 Emiya 家今天的饭 正难则反.考虑计算不合法方案.一个方案不合法一定存在一个主食,使得该主食在多于一半的方法中出现. 枚举这个&q ...
- SpringBoot多数据库连接(mysql+oracle)
出于业务需求,有时我们需要在spring boot web应用程序中配置多个数据源并连接到多个数据库. 使用过Spring Boot框架的小伙伴们,想必都发现了Spring Boot对JPA提供了非常 ...
- CSS样式基础2
CSS: 一.常用样式:字体,颜色,背景 二.布局:浮动 定位 标签特性 三.标签盒子模型: 边距 边框 四.动画:旋转 渐变 注意:子标签会继承父标签的样式但不是所有的样式都会被继承. 1.1 ...
- react 阻止事件传递/冒泡
当我们设计界面时,在以下情况会需要阻止元素/组件内的事件阻断,不被上层触发: 弹出提示框,期望点击框外空白区域可以关闭弹框.点击框内不关闭弹框 组件设计时,期望点击全局/点击指定元素时,显示不一样的交 ...
- jmeter单接口和多接口测试
@@@@@@@@@@@@@@@ # 路漫漫其修远 最近接触到了多接口串联,接口串联的技术会在其他帖子有说明,其核心技术点就是通过正则表达式和变量来实现接口的关联.目前为止呢笔者用到的地方还只有一个,就 ...