【转】设计模式-观察者模式
设计模式-观察者模式
定义
观察者模式(有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或 从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各 观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
基本简介
(1)抽象主题(Subject)
持有一个观察者对象的集合,提供增加,删除观察者对象的接口,当需要关注的状态变化时候,需要通知所有持有的观察者对象。
(2)具体主题(Concrete Subject)
被观察者的具体实现...
(3)抽象观察者(Observer)
定义一个接口,在接受通知时候更新状态
(4)具体观察者(Concrete Observer)
观察者的具体实现...
UML图
示例
(1.1)抽象主题类Subject
/// <summary>
/// 抽象主题
/// </summary>
public abstract class Subject
{
/// <summary>
/// 所有观察者对象
/// </summary>
private List<Observer> observers = new List<Observer>();
/// <summary>
/// 增加观察者对象
/// </summary>
/// <param name="observer"></param>
public void AddObserver(Observer observer)
{
observers.Add(observer);
}
/// <summary>
/// 移除观察者对象
/// </summary>
/// <param name="observer"></param>
public void RemoveObserver(Observer observer)
{
observers.Remove(observer);
}
/// <summary>
/// 发送通知
/// </summary>
public void Notify()
{
foreach (var ob in observers)
{
ob.Update();
}
}
}
(1.2)具体主题类ConcreteSubject
/// <summary>
/// 具体通知者
/// </summary>
public class ConcreteSubject : Subject
{
/// <summary>
/// 具体观察者状态
/// </summary>
public string SubjectState { get; set; }
}
(1.3)抽象观察者类
/// <summary>
/// 观察者类
/// </summary>
public abstract class Observer
{
public abstract void Update();
}
(1.4)具体观察者类
/// <summary>
/// 具体观察者
/// </summary>
public class ConcreteObserver : Observer
{
public string observerState { get; set; }
public string Name { get; set; }
public ConcreteSubject subjcSubject { get; set; }
public ConcreteObserver(ConcreteSubject subject, string name)
{
this.Name = name;
this.subjcSubject = subject;
}
public override void Update()
{
observerState = subjcSubject.SubjectState;
System.Console.WriteLine("the observer's state of {0} is {1}", Name, observerState);
}
}
(1.5)控制台调用
class Program
{
static void Main(string[] args)
{
ConcreteSubject subject = new ConcreteSubject();
subject.AddObserver(new ConcreteObserver(subject, "ObA"));
subject.AddObserver(new ConcreteObserver(subject, "ObB"));
subject.AddObserver(new ConcreteObserver(subject, "ObC"));
subject.SubjectState = "Ready";
subject.Notify();
System.Console.ReadKey();
}
}
(1.6)运行结果
优缺点
C#委托改版
我们以一个主题通知发送消息的例子来演示
(1.1)抽象主题
/// <summary>
/// 抽象主题
/// </summary>
public interface ISubject
{
void Notify();
}
(1.2)声明委托和具体主题
/// <summary>
/// 声明委托
/// </summary>
public delegate void MsgEvent();
/// <summary>
/// 具体主题
/// </summary>
public class ConcreteSubject : ISubject
{
/// <summary>
/// 定义委托事件
/// </summary>
public event MsgEvent MsgAction;
/// <summary>
/// 执行通知
/// </summary>
public void Notify()
{
if (MsgAction != null)
MsgAction();
}
}
(1.3)添加具体观察者 站内信,邮件,短信
/// <summary>
/// 站内信
/// </summary>
public class InsideLetterMsg
{
/// <summary>
/// 发送站内信
/// </summary>
public void SendInsideLetterMsg()
{
Console.WriteLine("发送站内信.....");
}
}
/// <summary>
/// 邮件
/// </summary>
public class MailMsg
{
/// <summary>
/// 发送邮件
/// </summary>
public void SendMailMsg()
{
Console.WriteLine("发送邮件.....");
}
}
/// <summary>
/// 短信
/// </summary>
public class SMSMsg
{
/// <summary>
/// 发送短信
/// </summary>
public void SendSMSMsg()
{
Console.WriteLine("发送短信.....");
}
}
(1.4)客户端调用
class Program
{
static void Main(string[] args)
{
ConcreteSubject subject = new ConcreteSubject();
//注册事件
subject.MsgAction += (new InsideLetterMsg()).SendInsideLetterMsg; //站内信
subject.MsgAction += (new MailMsg()).SendMailMsg; //邮件
subject.MsgAction += (new SMSMsg()).SendSMSMsg; //短信
//开始发送消息了
subject.Notify();
Console.ReadKey();
}
}
(1.5)结果
这个例子我们更多关注的是行为,主题对于观察者行为的执行和通知。我们只需要在调用的时候将观察者的方法注册到主题中即可。省去了主题需要维护观察者对象,循环调用观察者对象方法的过程。顺带我们也看一下我们创建的委托具体是what?
委托看一看
(1.1)看图说话
(1.2)System.MulticastDelegate
_invocationList通常这个字段为null,当我们构造一个委托链是,他可以引用一个委托数组,也就是说我们给委托+=方法时候,实际是操作它.
我们可以推断出当我们调用委托方法时候,代码大致是这样的(下面代码不是可运行的代码,只是预估大概的逻辑,仅供观看),不知道在观察者这块顺带写了下委托是不是有点
跑偏,委托这里只是顺带提一下,更多的知识面肯定没涉及到,只是帮助大家理解下.
//从委托链中获取
Delegate[] deleagetset = _invocationList as Delegate[];
if (deleagetset != null)
{
foreach (MsgAction m in deleagetset)
{
m(value); //调用每个委托
}
}
else
{
//当前不是委托链 直接 invoke
_methodPtr.Invoke(_target, value);
}
上边的例子只是单纯的循环,中途有一个调用委托失败都没有健壮的处理,所以MulticastDelegate类提供了另一个实例方法GetInvocationList,用于显示调用链中的每一个委托,具体大家可以查阅相关资料。That's all!
文章代码链接:https://files.cnblogs.com/files/mongo/BlogObserver.zip