事实说明什么是观察者定义:
相信大家都聊过QQ、WeChat,那我们就用这个来讲述什么事观察者模式。就拿qq来说吧,我们大家都有三到好几个qq群,而我们都是qq群里面的一员,在我们没有屏蔽群消息的前提下,群里只要有任何一个人说话,我们所有人都会收到消息,这个问题在加强朋友间交流的同时,也给部分人造成了些许困扰,所有就有了屏蔽群消息这个东西。那现在我们来分析一下,我们怎样才能接受群消息呢,首先我们要加群,要注册进去。而后,我们每个人才能随时接收群里发送的消息。再说一个就是我们的飞信等各种交流工具,相信大家都不陌生了吧。
定义总结:
观察者模式,也被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式类图:
观察者模式模式分析:
角色解析:
1、抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2、具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3、抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4、具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
作用意义(能解决什么问题?)
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
类图对应代码:
<span style="font-size:18px;"> /// <summary>
/// 抽象主题类
/// </summary>
public abstract class Subject
{
private IList<Observer> observers = new List<Observer>();
/// <summary>
/// 增加观察者
/// </summary>
/// <param name="observer"></param>
public void Attach(Observer observer)
{
observers.Add(observer);
}
/// <summary>
/// 移除观察者
/// </summary>
/// <param name="observer"></param>
public void Detach(Observer observer)
{
observers.Remove(observer);
}
/// <summary>
/// 向观察者(们)发出通知
/// </summary>
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
/// <summary>
/// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
/// </summary>
public abstract class Observer
{
public abstract void Update();
}
/// <summary>
/// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
/// </summary>
public class ConcreteSubject : Subject
{
private string subjectState;
/// <summary>
/// 具体观察者的状态
/// </summary>
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
/// <summary>
/// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调
/// </summary>
public class ConcreteObserver : Observer
{
private string observerState;
private string name;
private ConcreteSubject subject;
/// <summary>
/// 具体观察者用一个具体主题来实现
/// </summary>
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
public ConcreteObserver(ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
/// <summary>
/// 实现抽象观察者中的更新操作
/// </summary>
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("The observer's state of {0} is {1}", name, observerState);
}
}
4.3 客户端代码
class Program
{
static void Main(string[] args)
{
// 具体主题角色通常用具体自来来实现
ConcreteSubject subject = new ConcreteSubject();
subject.Attach(new ConcreteObserver(subject, "Observer A"));
subject.Attach(new ConcreteObserver(subject, "Observer B"));
subject.Attach(new ConcreteObserver(subject, "Observer C"));
subject.SubjectState = "Ready";
subject.Notify();
Console.Read();
}
}
</span>
这就是我们的基础的观察者模式的基础代码,但是这样并不是最好的,我们还有更好的,相信大家也学习过事件,一个可控的handle,下面我们就把两者结合起来。
观察者模式+事件实现,我们的单个具体观察者类不变,在主题类中声明一个事件来承接所有的方法。
<span style="font-size:18px;"> class ConcreteSubject:Subject{
public event EventHandler Update; //声明一个事件Update,类型为委托EventHandler
private string action;
public void Notify(){ //通知观察者方法
Update();
}
public string SubjectState{ //状态实体接收单位
get {return action;}
set {action=value;}
}
}
//客户端代码
Subject subject=new Subject();
ContreteObjectA coA=new ContreteObjectA();
ContreteObjectB coB=new ContreteObjectB();</span>
<span style="font-size:18px;"> </span>
<span style="font-size:18px;"> //注册观察者
subject.Update+=new EventHandler(coA.cometrue);<span style="font-family: Arial, Helvetica, sans-serif;">//这里是具体的观察者的行动方式(个性化重写,实现)</span>
subject.Update+=new EventHandler(coB.cometrue);/<span style="font-family: Arial, Helvetica, sans-serif;">/这里是具体的观察者的行动方式(个性化重写,实现)</span>
subject.SubjectState="当前状态";
subject.Notify();</span>
这样,我们就直接在观察者的具体实现类中定义好自己的实现方式,然后注册到事件中就可以了,这样也就实现了动态的添加注册者一事。
模式优点:
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
模式缺点:
依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
模式应用场景:
1、当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
2、一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
总结:
1、委托,委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法有相同的行为。委托方法可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数(方法)的的抽象,是函数的“类”,委托的实例代表一个(或多个)具体的函数,它可以是多播的。
2、事件,事件基于委托,为委托提供了一种发布/订阅机制。事件的订阅与取消与我们刚才讲的观察者模式中的订阅与取消类似,只是表现形式有所不同。在观察者模式中,订阅使用方法Attach()/Add()来进行;在事件的订阅中使用“+=”。类似地,取消订阅在观察者模式中用Dettach()/Delete(),而事件的取消用“-=”。