zoukankan      html  css  js  c++  java
  • 3 观察者模式

    一、观察者模式总览

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

    UML类图如下:

    image

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

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

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

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

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

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

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

    二、C#中的观察者模式

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

    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.IObsverableIObserver接口

    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);
       }

    相当于多做了一层封装。

  • 相关阅读:
    poj 3070 矩阵快速乘
    将数字放大显示
    hdu 火车入队 stack
    linq to Entity 数据库除了有主键还有唯一索引,是不是不能更新
    整理:C#写ActiveX, 从代码到打包到签名到发布的示例
    Java—FileOperator
    第二章-递归与分治策略
    第四章-贪心算法
    第五章-回溯法
    Linux中C程序调试、makefile
  • 原文地址:https://www.cnblogs.com/zhixin9001/p/5782197.html
Copyright © 2011-2022 走看看