下面是一些关于这个Observer的基本一些概念,在很多地方都能看到,这里我归纳这这里便于以后查阅:
一、发布订阅模型(pub-sub)
二、动机(Motivation)
在软件构建过程中,我们需要为某些对象建立一种 "通知依赖关系" ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得
到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
三、意图(Intent)
定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新 ——《设计模式》GoF
四、结构
五、Observer模式的几个要点
• 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
• 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。观察者自己决定是否需要订阅通知,目标对象对此一无所
知。
• 在C#的event中,委托充当了抽象的Observer接口,而提供事件的对象充当了目标对象。委托是比抽象Observer接口更为松耦合的设计。
六、项目中运用的发布订阅模式的实际例子:(这里实际上运用了observer模式的扩展)需求是:当一个对象的状态发生了变化(这里是传入一个消息给一个对象),那么所有监听这个对象的其他对象会根据指定的接收对象的类型调用指定对象的方法:我们都很清楚的了解到observer模式主要是用于当一个对象的状态发生变化的时候,会自动的通知订阅的其他对象,也就是说会把当前的消息传递给其他对象进行处理。但是有一个问题是,如果其他对象接收到的消息是由限制的,像某个对象只能接收指定类型的消息等,这样的话就需要在以前的observer模式上进行补充:
下面是项目中关于这个模式的的结构如图:
首先来看看Listener文件夹下的一个文件(其他几个文件类似)
[KnowType(typeof(float))]
public class DesignApprovalListener:IActionListener
{
public bool Run(object value)
{
return true;
}
}
其中KnowType是一个自定义的属性,代码如下:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class KnowTypeAttribute : Attribute
{
private string m_typeName;
public string TypeName
{
get { return m_typeName; }
}
public KnowTypeAttribute(Type modelType)
{
this.m_typeName = modelType.FullName;
}
}
IActionListener是一个接口:
public interface IActionListener
{
/// <summary>
/// 订阅接受方法
/// </summary>
/// <param name="value">Domain Model or Data Entity</param>
/// <returns>执行成功返回True,否则为false</returns>
bool Run(object value);
}
其中的核心方法是通过反射得到所有监听的对象所需要接受对象的类型,这样就可以调用指定对象的方法,而不是调用所有监听者的方法:下面是这个方法的核心:
Core文件夹下的MonitorFactory.cs文件就是完成这一个功能,代码如下:
Code
public static bool Publisher(object arg)
{
bool result = false;
if (configuration != null && configuration.Listeners != null && configuration.Listeners.Count > 0)
{
RegisteredListener listener = null;
foreach (ListenerItem item in configuration.Listeners)
{
if (item.Valid)
{
listener = ActivatorListener(item.ClassName);
if (listener != null)
{
if (listener.RegisteredTypes == null || listener.RegisteredTypes.Length == 0)
{
result= listener.CurrentListener.Run(arg);
}
else
{
foreach (KnowTypeAttribute attributeItem in listener.RegisteredTypes)
{
if (arg.GetType().FullName == attributeItem.TypeName)
{
result=listener.CurrentListener.Run(arg);//这里是调用指定对象的方法
}
}
}
}
}
}
}
return result;
}
Code
/// <summary>
/// 创建Listener实例并获取Attribute
/// </summary>
/// <param name="className"></param>
/// <returns></returns>
private static RegisteredListener ActivatorListener(string className)
{
RegisteredListener result = null;
if (registeredContainer.ContainsKey(className))
{
result = registeredContainer[className];
}
else
{
Type type = Type.GetType(className);
if (type != null)
{
KnowTypeAttribute[] registerType = type.GetCustomAttributes(typeof(KnowTypeAttribute), false) as KnowTypeAttribute[];
IActionListener listenerInstance = Activator.CreateInstance(type) as IActionListener;
result = new RegisteredListener(listenerInstance, registerType);
registeredContainer.Add(className, result);
}
}
return result;
}
注册监听对象对象是通过代码指定的,当然可以通过一个xml文件来配置节点来实现,那样会更加灵活
Code
private static Dictionary<string, RegisteredListener> registeredContainer;
private static MonitorConfiguration configuration;
static MonitorFactory()
{
configuration = new MonitorConfiguration();
configuration.Listeners = new List<ListenerItem>();
ListenerItem item = new ListenerItem();
item.ClassName = "ProjectEstablishRequestListener";
configuration.Listeners.Add(item);
item = new ListenerItem();
item.ClassName = "ProjectApprovalListener";
configuration.Listeners.Add(item);
item = new ListenerItem();
item.ClassName = "DesignApprovalListener";
configuration.Listeners.Add(item);
registeredContainer = new Dictionary<string, RegisteredListener>();
foreach (ListenerItem listener in configuration.Listeners)
{
if (listener.Valid)
{
ActivatorListener(listener.ClassName);
}
}
}
这里就不展示其他代码了,总之思想就是这样,通过在Listener的类文件中通过属性来制定这个对象接受的消息类型,最后遍历所有的监听者对象看是否满足指定的消息类型,最后调用指定的对象的方法。这样就达到了项目中的需求。
推荐资源
* 《设计模式:可复用面向对象软件的基础》GoF
* 《面向对象分析与设计》Grady Booch
* 《敏捷软件开发:原则、模式与实践》Robert C. Martin
* 《重构:改善既有代码的设计》Martin Fowler
* 《Refactoring to Patterns》Joshua Kerievsky
更多MSDN资源
* MSDN中文网站
http://www.microsoft.com/china/msdn
* MSDN中文网络广播
http://www.msdnwebcast.com.cn/
* MSDN Flash
http://www.microsoft.com/china/newsletter/case/msdn.aspx
* MSDN开发中心
http://www.microsoft.com/china/msdn/DeveloperCenter/default.mspx