首页 > 技术文章 > C#设计模式之3:观察者模式

pangjianxin 2017-12-04 17:51 原文

C#中已经实现了观察者模式,那就是事件,事件封装了委托,使得委托的封装性更好,在类的内部定义事件,然后在客户端对事件进行注册:

 public class Subject
    {
        public event Action<int> MyEvent;
        public async Task ExecuteEvent()
        {
            for (int i = 0; i < 100; i++)
            {
                await Task.Delay(TimeSpan.FromSeconds(0.1));
                Console.Write(".");
                if (i>50)
                {
                    MyEvent(i);
                    return;
                }
            }            
        }

    }
 class Program
    {
        static void Main(string[] args)
        {
            Subject sub = new Subject();
            sub.MyEvent += (a) =>
            {
                Console.WriteLine($"the temprature is {a} now ,please shutdown!");              
            };
            Task task= sub.ExecuteEvent();          
            Console.ReadKey();
        }
    }

可以说在C#中实现观察者模式是非常方便的。

观察者模式的定义:观察者模式定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,他的所有依赖着都会收到通知并自动更新。

上面的例子可能比较简单,Subject类充当的就是一个主题,或者叫发布者,使用+=注册的lambda充当的就是一个订阅者,也就是Observer,(lambda表达式会生成一个匿名的类,更准确的说实际上这个匿名的类就是一个Observer)将会有很多的类似于这样的订阅者来对Subject的MyEvent事件进行注册,所以Subject和Observer是一对多的。当我们执行Subject中的ExecuteEvent方法时,就是在满足一定条件后发出通知,而Observer就会去执行相应的动作,这就是观察者模式。因为这个模式涉及到了对象和对象之间的依赖,这么这里又涉及到一个概念,那就是耦合。

设计原则:为了交互对象之间的松耦合而努力。

 

手动实现的观察者模式(java)

还是以headfirst设计模式这本书上的例子为依据,这个例子讲的是一个气象站(ISubject)和很多布告板(Observer)的故事,先上类图:

 

 观察者模式中有两个角色,一个是Subject,主题角色,这个角色用来发布消息,另一个是Observer,观察者,用来接收消息。Subject和Observer的关系是一对多。

 /// <summary>
    /// 定义一个主题对象的接口,主题对象可以发出通知。
    /// 被观察者(IObserver)接受并做出相应的动作。
    /// 主题对象和观察者之间是一对多的关系。
    /// </summary>
    public interface ISubject
    {
        void RegisterObserver(IObserver observer);
        void RemoveObserver(IObserver observer);
        void NotifyObservers();
    }

    public interface IObserver
    {
        void Update(float temp, float humidity, float pressure);
    }

    public interface IDisplay
    {
        void Display();
    }
    /// <summary>
    /// ConcreteSubject角色
    /// </summary>
    public class WeatherData:ISubject
    {
        private readonly IList<IObserver> _observers=new List<IObserver>();
        public float Temp { get; set; }
        public float Humidity { get; set; }
        public float Pressure { get; set; }
        public void RegisterObserver(IObserver observer)
        {
           _observers.Add(observer);
        }

        public void RemoveObserver(IObserver observer)
        {
            _observers.Remove(observer);
        }

        public void NotifyObservers()
        {
            foreach (IObserver item in _observers)
            {
               item.Update(Temp,Humidity,Pressure);
            }
        }


        public void SetMeasurements(float temp, float humidity, float pressure)
        {
            Temp = temp;
            Humidity = humidity;
            Pressure = pressure;
            NotifyObservers();            
        }
    }
    public class CurrentConditionDisplay:IObserver,IDisplay
    {
        private float _temperature;
        private float _humidity;
        private ISubject _weatherData;
        public CurrentConditionDisplay(ISubject weatherData)
        {
            _weatherData = weatherData;
            _weatherData.RegisterObserver(this);
        }
        public void Update(float temperature, float humidity, float pressure)
        {
            _temperature = temperature;
            _humidity = humidity;
            Display();
        }
        public void Display()
        {
            Console.WriteLine($"out temperature is {_temperature},out humidity is {_humidity}");
        }
       
    }

 

推荐阅读