第二章 观察者模式2

C#内置观察者模式(消息推送模式)

摘自:MSDN
对比邮局和报纸订阅客户的关系,属于一对多的关系,消息更新即向客户推送消息。
在.net框架中已经提供了预定义的观察者模式的接口。
泛型接口IObservable<T>用来实现可观察者,IObserver<T>用来实现观察者。T是提供数据的类。
在可观察者内只调用观察者内的来自接口的方法,在观察者内只调用可观察者内来自接口的方法。这样就将观察者和可观察者解耦了,防止彼此藕断丝连。
订阅的工作由订阅者发起public virtual void Subscribe(IObservable<Location> provider),订阅的完成是在可订阅者内部完成public virtual void Subscribe(IObservable<Location> provider),订阅者调用可订阅者的接口方法Subscribe。其他取消订阅,报错,完成传送等和此类似。
这里写图片描述

具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 内置观察者模式
{
    class Program
    {
        static void Main(string[] args)
        {
            // 定义两个观察者和两个被观察者
            var provider = new LocationTracker();
            var reporter1 = new LocationReporter("FixedGPS");
            reporter1.Subscribe(provider); // 观察者发起订阅,在可观察者内完成订阅

            var reporter2 = new LocationReporter("MobileGPS");
            reporter2.Subscribe(provider);

            provider.TrackLocation(new Location(47.6456, -122.1312));
            reporter1.Unsubscribe();
            provider.TrackLocation(new Location(47.6677, -122.1199));
            provider.TrackLocation(null);
            provider.EndTransmission();

            Console.ReadKey();
        }
    }

    // 观察者
    public class LocationReporter : IObserver<Location>
    {
        private IDisposable _unsubscriber; // 取消订阅类实例

        public LocationReporter(string name)
        {
            Name = name;
        }

        // 观察者名称
        public string Name { get; }

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

        // 完成数据传送,取消订阅,实现观察者接口的方法,在可观察者内调用
        public virtual void OnCompleted()
        {
            Console.WriteLine($"The Location Tracker has completed transmitting data to {Name}.");
            Unsubscribe();
        }

        // 发生错误,实现观察者接口的方法,在可观察者内调用
        public virtual void OnError(Exception e)
        {
            Console.WriteLine($"{Name}: The location cannot be determined.");
        }

        // 接收订阅的数据,实现观察者接口的方法,在可观察者内调用
        public virtual void OnNext(Location value)
        {
            Console.WriteLine($"{Name}: The current location is {value.Latitude}, {value.Longitude}");
        }

        // 取消订阅
        public virtual void Unsubscribe()
        {
            _unsubscriber.Dispose();
        }
    }

    // 可观察者
    public class LocationTracker : IObservable<Location>
    {
        public LocationTracker()
        {
            _observers = new List<IObserver<Location>>();
        }

        private readonly List<IObserver<Location>> _observers;

        // 订阅
        public IDisposable Subscribe(IObserver<Location> observer)
        {
            if (!_observers.Contains(observer))
                _observers.Add(observer);
            return new Unsubscriber(_observers, observer); // 返回取消订阅类,传入参数为所有订阅者和当前订阅者
        }

        // 取消订阅
        private class Unsubscriber : IDisposable
        {
            private readonly List<IObserver<Location>> _observers; // 所有订阅者
            private readonly IObserver<Location> _observer; // 当前订阅者

            public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
            {
                _observers = observers;
                _observer = observer;
            }

            // 取消订阅
            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }

        public void TrackLocation(Location? loc)
        {
            foreach (var observer in _observers)
            {
                if (!loc.HasValue)
                    observer.OnError(new LocationUnknownException());
                else
                    observer.OnNext(loc.Value);
            }
        }

        // 取消所有订阅者
        public void EndTransmission()
        {
            foreach (var observer in _observers.ToArray())
                if (_observers.Contains(observer))
                    observer.OnCompleted();

            _observers.Clear();
        }
    }

    //  提供通知信息的对象
    public struct Location
    {
        public Location(double latitude, double longitude)
        {
            this.Latitude = latitude;
            this.Longitude = longitude;
        }

        public double Latitude { get; }

        public double Longitude { get; }
    }

    // 定制错误类
    public class LocationUnknownException : Exception
    {
        internal LocationUnknownException()
        { }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值