3 观察者模式

一、观察者模式总览

观察者模式定义了对象之间的一对多依赖,让多个观察者对象同时监听一个主题对象,当主题对象改变状态时,它的所有依赖者都会收到通知并自动更新。

UML类图如下:

image

Subject为主题抽象对象,Observer为观察者抽象对象,主题对象中规定了“订阅”、“取消订阅”、“通知”等必要的方法。所以这是多个观察者依赖同一个主题对象,是一种多对一的依赖。

至于实现了主题和观察者接口的实体对象,实体观察者之所以要关联实体主题,是因为实体观察者要从实体主题那里拿到需要的数据。

观察者公开了Update()方法让主题在需要的时候调用,从而通知观察者改变状态。另一方面,观察者关联了主题,可以从主题拿到需要的数据。

使用这种结构,使主题与观察者之间的耦合降到最低,观察者可以随时对主题订阅或取消订阅,而且一个系统的观察者可以同时成为另一个系统的主题。

关于数据的传递,站在观察者的角度来看,有“推(push)”和“拉(pull)”两种模式。

push模式,是在主题调用Update通知观察者时,把数据全部传递给观察者,这是一种从上至下的模式,简单暴力,屏蔽了不同观察者之间的个性,所有观察者接收同样的通知和数据。

pull模式,主题调用Update只是起到通知的作用,具体获取数据的方式由各个观察者实体决定,相对push模式,这种模式更加灵活。

 

二、C#中的观察者模式

C#中用到观察者模式的机制有:事件、IObsverable\IObserver接口

1.事件:

如下为简单的示例代码,可以模仿了观察者模式的命名

//主题

class Subject6 

{
    public delegate void NotifyHandler(int param);
    public event NotifyHandler Notify;
    public void SetParam(int i)
    {
        Notify(i);
    }
}
//观察者

class Observer6
{
    string name;
    public Observer6(string name)
    {
        this.name = name;
    }

    public void Update(int i)
    {
        Console.WriteLine(name + "--" + i);
    }
}

//控制台调用代码

static void Main(string[] args)
{
    Subject6 s6 = new Subject6();
    s6.Notify += new Observer6("A").Update;
    s6.Notify += new Observer6("B").Update;

    s6.SetParam(1);
    s6.SetParam(2);
    Console.ReadKey();
}

运行结果:

A--1
B--1
A--2
B--2

2.IObsverable\IObserver接口

MSDN用了GPS的例子https://msdn.microsoft.com/zh-cn/library/dd990377(v=vs.100).aspx

类图如下

image

//控制台调用代码

static void Main(string[] args)
{

    LocationTracker provider = new LocationTracker();
    LocationReporter reporter1 = new LocationReporter("GPS1");
    LocationReporter reporter2 = new LocationReporter("GPS2");
    reporter1.Subscribe(provider);
    reporter2.Subscribe(provider);

    provider.TrackLocation(new Location(1, 2));
    provider.TrackLocation(new Location(2,4));
    provider.EndTransmission();
   Console.ReadKey();
}

Unsubscriber是LocationTracker的内部类,在订阅的时候返回给订阅者Observer,Unsubscriber用于取消订阅,这样就相当于把取消订阅的权利交给了订阅者自身。

此外,与前面的几种实现方式不同的是,观察者主动订阅主题(reporter1.Subscribe(provider)),而不是主题添加观察者。reporter1.Subscribe的细节是这样的:

   public virtual void Subscribe(IObservable<Location> provider)
   {
      if (provider != null) 
         unsubscriber = provider.Subscribe(this);
   }

相当于多做了一层封装。

posted @ 2016-08-17 22:37  zhixin9001  阅读(283)  评论(0编辑  收藏  举报