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

    相当于多做了一层封装。

  • 相关阅读:
    bzoj 1086 [SCOI2005]王室联邦——思路
    bzoj 3809 Gty的二逼妹子序列——莫队+分块
    bzoj 3781 小B的询问——分块
    bzoj 3309 DZY Loves Math——反演+线性筛
    洛谷 1079 Vigenère 密码——模拟水题
    洛谷 1082 同余方程——exgcd(水题)
    bzoj2662 [BeiJing wc2012]冻结 ——分层图
    bzoj2242 [SDOI2011]计算器——BSGS
    bzoj1008 [HNOI2008]越狱——快速幂
    bzoj1607 [Usaco2008 Dec]Patting Heads 轻拍牛头——暴力
  • 原文地址:https://www.cnblogs.com/zhixin9001/p/5782197.html
Copyright © 2020-2023  润新知