消息总线设计系列之 - 调停者模式
2008-05-16 17:44
411 查看
自从写了上一篇消息总线设计系列之 - 观察者模式之后,已经好长时间了,实在惭愧,现在抽出时间了,写下这一篇。观察者模式的特点是每个观察者对象可以定阅一个或多个不同类型的主题对象,每个主题对象包括一个或多个相同类型的观察者对象,他们之间是高度耦合并且直接进行通讯。 如果项目中用到大量的观察者模式之后,你会发现系统中的观察者和主题对象形成了一张错乱无章的关系网,非常难以维护。调停者模式就是为了解决这种错乱无章的对象网之间的通讯问题的,屏蔽了对象之间的直接通讯功能,并充当了转发和路由能能。(为了更清楚的理解这篇文章,你可以先看看上一篇文章消息总线设计系列之 - 观察者模式)
总线接口设计的要素是:
1. 总线接口应该包含一个主题的字典集合,字典的键就是主题事件的类型。
2. 消息发送(通过消息对象可以得到消息类型,然后通过消息类型取出主题对象,然后发送操作就路由到主题对象上)
3. 总线接口应该提供一个主题对象的一个泛型工厂,方便用户注册观察者
消息总线接口设计如下:
public interface IMessageRouter
{
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
void Send(object message);
/// <summary>
/// 得到或注册一个指定消息的主题对象(主题对象的泛型工厂)
/// </summary>
/// <typeparam name="Message"></typeparam>
/// <returns></returns>
Subject<Message> Subject<Message>();
} 为了适应消息总线,咱们需要把上一篇介绍的观察者模式的代码稍微修改一下
/// <summary>
/// 抽象主题
/// </summary>
public abstract class Subject
{
/// <summary>
/// 观察者委托
/// </summary>
public abstract Delegate Delegate { get;}
//委托参数类型
public abstract Type MessageType { get;}
}
public class Subject<Message> : Subject
{
// 利用委托对象做为 观察者列表
private ObserverDelegate<Message> observerList;
/// <summary>
/// 注册或移除观察者
/// </summary>
public event ObserverDelegate<Message> Observers
{
add //注册观察者
{
observerList += value;
}
remove//移除观察者
{
observerList -= value;
}
}
/// <summary>
/// 观察者委托
/// </summary>
public override Delegate Delegate { get { return observerList; } }
/// <summary>
/// 委托参数类型
/// </summary>
public override Type MessageType { get { return typeof(Message);}}
}
准备工作已经到位了,下面就一步一步介绍实现方案了
1. 构造一个主题字典对象
Dictionary<Type, Subject> subjectList = new Dictionary<Type, Subject>(); 2. 实现主题的泛型工厂方法
public Subject<Message> Subject<Message>()
{
Type msgType = typeof(Message);
Subject<Message> subject = null;
if (!subjectList.ContainsKey(msgType))
{
subject = new Subject<Message>();
subjectList[msgType] = subject;
}
else
{
subject = subjectList[msgType] as Subject<Message>;
}
return subject;
} 3. 实现消息发送方法
public void Send(object message)
{
//空消息直接返回
if (message == null)
return;
//取出消息类型
Type msgType = message.GetType();
//根据消息类型得到主题对象
Subject subject = subjectList[msgType];
if (subject == null)
{
return;
}
//如果没有观察者来定阅了,就移除该主题对象
if(subject.Delegate == null)
{
subjectList.Remove(msgType);
return;
}
//取出主题对象的所有观察者集合
Delegate[] observers = subject.Delegate.GetInvocationList();
//给所有观察者对象发通知
foreach (Delegate observe in observers)
{
try
{
observe.DynamicInvoke(message);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
} 我们已完成消息总线的所有设计,下面看看简单的应用,消息总线常常做为一个公共类即全局对象,所以咱们写一个单例模式的消息总线,该总线继承于上面所实现的,代码如下:
class LocalMessageRouter:MessageRouter
{
private LocalMessageRouter(){}
public static readonly IMessageRouter Instance = new LocalMessageRouter();
}
测试代码:
class Sample5:ICommand
{
public void Execute()
{
LocalMessageRouter.Instance.Subject<string>().Observers +=new ObserverDelegate<string>(OnHelloString);
LocalMessageRouter.Instance.Subject<string>().Observers += new ObserverDelegate<string>(OnHelloString2);
LocalMessageRouter.Instance.Subject<string[]>().Observers += new ObserverDelegate<string[]>(OnHelloStringArray);
LocalMessageRouter.Instance.Subject<Message>().Observers += new ObserverDelegate<Message>(OnMessage);
LocalMessageRouter.Instance.Send("ZhangSan");
LocalMessageRouter.Instance.Send(new string[] { "LiSi", "ZhangSan" });
LocalMessageRouter.Instance.Send(new Message("李四", "张三"));
}
private class Message
{
public readonly string Sender;
public readonly string To;
public Message(string sender, string to)
{
this.Sender = sender;
this.To = to;
}
}
static void OnMessage(Message e)
{
Console.WriteLine(e.Sender + " Hello " + e.To);
}
static void OnHelloString2(string e)
{
Console.WriteLine("你好 " + e);
}
static void OnHelloStringArray(string[] e)
{
Console.WriteLine(e[0] + " hello " + e[1]);
}
static void OnHelloString(string e)
{
Console.WriteLine("Hello " + e);
}
}
测试结果:
Hello ZhangSan
你好 ZhangSan
LiSi hello ZhangSan
李四 Hello 张三
下面在给出一个用消息总线模拟实现的IM截图
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/26/58c144d4e1a8d878c2d4a996866206a1.jpg)
最后附上源代码,下一篇介绍怎样彻底解决委托与事件的内存泄漏问题
总线接口设计的要素是:
1. 总线接口应该包含一个主题的字典集合,字典的键就是主题事件的类型。
2. 消息发送(通过消息对象可以得到消息类型,然后通过消息类型取出主题对象,然后发送操作就路由到主题对象上)
3. 总线接口应该提供一个主题对象的一个泛型工厂,方便用户注册观察者
消息总线接口设计如下:
public interface IMessageRouter
{
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
void Send(object message);
/// <summary>
/// 得到或注册一个指定消息的主题对象(主题对象的泛型工厂)
/// </summary>
/// <typeparam name="Message"></typeparam>
/// <returns></returns>
Subject<Message> Subject<Message>();
} 为了适应消息总线,咱们需要把上一篇介绍的观察者模式的代码稍微修改一下
/// <summary>
/// 抽象主题
/// </summary>
public abstract class Subject
{
/// <summary>
/// 观察者委托
/// </summary>
public abstract Delegate Delegate { get;}
//委托参数类型
public abstract Type MessageType { get;}
}
public class Subject<Message> : Subject
{
// 利用委托对象做为 观察者列表
private ObserverDelegate<Message> observerList;
/// <summary>
/// 注册或移除观察者
/// </summary>
public event ObserverDelegate<Message> Observers
{
add //注册观察者
{
observerList += value;
}
remove//移除观察者
{
observerList -= value;
}
}
/// <summary>
/// 观察者委托
/// </summary>
public override Delegate Delegate { get { return observerList; } }
/// <summary>
/// 委托参数类型
/// </summary>
public override Type MessageType { get { return typeof(Message);}}
}
准备工作已经到位了,下面就一步一步介绍实现方案了
1. 构造一个主题字典对象
Dictionary<Type, Subject> subjectList = new Dictionary<Type, Subject>(); 2. 实现主题的泛型工厂方法
public Subject<Message> Subject<Message>()
{
Type msgType = typeof(Message);
Subject<Message> subject = null;
if (!subjectList.ContainsKey(msgType))
{
subject = new Subject<Message>();
subjectList[msgType] = subject;
}
else
{
subject = subjectList[msgType] as Subject<Message>;
}
return subject;
} 3. 实现消息发送方法
public void Send(object message)
{
//空消息直接返回
if (message == null)
return;
//取出消息类型
Type msgType = message.GetType();
//根据消息类型得到主题对象
Subject subject = subjectList[msgType];
if (subject == null)
{
return;
}
//如果没有观察者来定阅了,就移除该主题对象
if(subject.Delegate == null)
{
subjectList.Remove(msgType);
return;
}
//取出主题对象的所有观察者集合
Delegate[] observers = subject.Delegate.GetInvocationList();
//给所有观察者对象发通知
foreach (Delegate observe in observers)
{
try
{
observe.DynamicInvoke(message);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
} 我们已完成消息总线的所有设计,下面看看简单的应用,消息总线常常做为一个公共类即全局对象,所以咱们写一个单例模式的消息总线,该总线继承于上面所实现的,代码如下:
class LocalMessageRouter:MessageRouter
{
private LocalMessageRouter(){}
public static readonly IMessageRouter Instance = new LocalMessageRouter();
}
测试代码:
class Sample5:ICommand
{
public void Execute()
{
LocalMessageRouter.Instance.Subject<string>().Observers +=new ObserverDelegate<string>(OnHelloString);
LocalMessageRouter.Instance.Subject<string>().Observers += new ObserverDelegate<string>(OnHelloString2);
LocalMessageRouter.Instance.Subject<string[]>().Observers += new ObserverDelegate<string[]>(OnHelloStringArray);
LocalMessageRouter.Instance.Subject<Message>().Observers += new ObserverDelegate<Message>(OnMessage);
LocalMessageRouter.Instance.Send("ZhangSan");
LocalMessageRouter.Instance.Send(new string[] { "LiSi", "ZhangSan" });
LocalMessageRouter.Instance.Send(new Message("李四", "张三"));
}
private class Message
{
public readonly string Sender;
public readonly string To;
public Message(string sender, string to)
{
this.Sender = sender;
this.To = to;
}
}
static void OnMessage(Message e)
{
Console.WriteLine(e.Sender + " Hello " + e.To);
}
static void OnHelloString2(string e)
{
Console.WriteLine("你好 " + e);
}
static void OnHelloStringArray(string[] e)
{
Console.WriteLine(e[0] + " hello " + e[1]);
}
static void OnHelloString(string e)
{
Console.WriteLine("Hello " + e);
}
}
测试结果:
Hello ZhangSan
你好 ZhangSan
LiSi hello ZhangSan
李四 Hello 张三
下面在给出一个用消息总线模拟实现的IM截图
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/26/58c144d4e1a8d878c2d4a996866206a1.jpg)
最后附上源代码,下一篇介绍怎样彻底解决委托与事件的内存泄漏问题
相关文章推荐
- 消息总线设计系列之 - 调停者模式 --拷贝自http://www.cnblogs.com/netcasewqs/archive/2008/05/16/1200926.html
- 消息总线设计系列之 - 观察者模式
- 事件触发、分发、observer机制----消息总线架构模式(中介者(调停者)设计模式)
- [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现
- 基于总线的消息服务(BBMS)的设计与实现
- Azure Messaging-ServiceBus Messaging消息队列技术系列8-服务总线配额
- MQ消息架构设计二(消息总线能否实现消息必达?)
- [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现
- 《解剖PetShop》系列之 一:系统架构设计 二:数据访问层之数据库访问设计 三:数据访问层之消息处理
- 事件触发、分发、observer机制----消息总线架构模式(中介者(调停者)设计模式)
- 基于Disruptor游戏服务器消息总线的设计
- 一步一步教你设计轻量级消息总线
- 消息总线授权设计
- 【设计模式系列】行为型模式之Status模式
- [Java] 设计模式之工厂系列 03- spring.properties 的键值读取 / Spring3.0 读取 比较
- 《企业集成模式.设计、构建及部署消息传递解决方案》学习笔记
- 设计模式系列:构建者模式
- 框架设计之菜鸟漫漫江湖路系列 三:初入江湖
- [.NET领域驱动设计实战系列]专题四:前期准备之工作单元模式(Unit Of Work)