设计模式-观察者模式


   1:观察者模式无疑是观察。举一个例子来说明一下观察者模式。比喻现在要开联合国(主题)大会,那么现在各国国家派出代表去参加(此时各国代表就是观察者)。代表把联合国商讨的结果带回来传递给国内人民,这个过程就是观察者模式。看下图

下面开始编码:

第一步:我们先看被观察者(就是主题),被观察者有什么特性呢,首先有观察者就是add,同时呢这个观察者不想观察了那就撤销delete,还有呢就是观察者观察到好的东西要通知告诉上层领导

那么这个接口我们就可以定义了

/// <summary>
    /// 主题接口
    /// </summary>
    public interface ISubject
    {
        /// <summary>
        /// 注册参加的代表
        /// </summary>
        /// <param name="observer">代表</param>
        void Add(string Name,IObserver observer);
        /// <summary>
        /// 删除参加的代表
        /// </summary>
        /// <param name="observer"></param>
        void Delete(string Name, IObserver observer);
        /// <summary>
        /// 通知各国的代表
        /// </summary>
        void Notify();
    }

第二步:我们该定义观察者了。观察者要干嘛呢,就是观察(其实就是监听,像不像奸细)得到信息了赶紧就去汇报,所以接口就比较好定义了就是传递信息(当然实际项目中就是得到信号以后你自己的操作)

/// <summary>
    /// 观察者(这里指的是各国派的代表)
    /// </summary>
    public interface IObserver
    {
        /// <summary>
        /// 代表通过本国民众
        /// </summary>
        void UpdateHoliday(string Message);
    }

第三步:实现被观察者

/// <summary>
    /// 实现主题
    /// </summary>
    public class Subject : ISubject {

        private Dictionary<string, IObserver> allObservers = new Dictionary<string, IObserver>(5);
        /// <summary>
        /// 通过信息
        /// </summary>
        public string PublishInfo { get; set; }

        /// <summary>
        /// 注册代表
        /// </summary>
        /// <param name="Name">代表名称</param>
        /// <param name="observer"></param>
        public void Add(string Name, IObserver observer) {
            if (allObservers.ContainsKey(Name)) {
                allObservers[Name] = observer;
            }
            else {
                allObservers.Add(Name, observer);
            }
        }
        /// <summary>
        /// 删除代表
        /// </summary>
        /// <param name="Name">代表名称</param>
        /// <param name="observer"></param>
        public void Delete(string Name, IObserver observer) {
            if (allObservers.ContainsKey(Name)) {
                allObservers.Remove(Name);
            }
        }
        /// <summary>
        /// 通知各国代表
        /// </summary>
        public void Notify() {
            foreach (var observer in allObservers) {
                observer.Value.UpdateHoliday(PublishInfo);
            }
        }

这里面的逻辑自己可以根据项目需要来定义

第四步:实现观察者

/// <summary>
    /// 日本
    /// </summary>
    public class JapanObserver : IObserver
    {
        /// <summary>
        /// 把假日更新
        /// </summary>
        /// <param name="Message"></param>
        public void UpdateHoliday(string Message)
        {
            Console.WriteLine("我是日本代表 通过广告转告民众:{0}", Message);
        }
    }

    /// <summary>
    /// 美国
    /// </summary>
    public class AmericaObserver : IObserver {
        public void UpdateHoliday(string Message) {
            Console.WriteLine("我是美国代表 通过广播转告民众:{0}", Message);
        }
    }

/// <summary>
    /// 中国
    /// </summary>
    public class ChinaObserver : IObserver {
        public void UpdateHoliday(string Message) {
            Console.WriteLine("我是中国代表 通过电视转告民众:{0}", Message);
        }
    }

/// <summary>
    /// 英国
    /// </summary>
    public class BritishObserver : IObserver {
        public void UpdateHoliday(string Message) {
            Console.WriteLine("我是英国代表 通过报纸转告民众:{0}", Message);
        }
    }

/// <summary>
    /// 德国
    /// </summary>
    public class GermanyObserver : IObserver {
        public void UpdateHoliday(string Message) {
            Console.WriteLine("我是德国代表 通过媒体转告民众:{0}", Message);
        }
    }

这里有5个不同的观察者,因为他们来自不同的国家(项目中可以根据实际情况)

第五步:运行看下结果

 总结:观察者模式定义了对象之间的一种联系,使得当一个对象改变状态时,所有其他对象可以相应的被通知到。通常,系统有一个新状态发布者,以及许多想要得到状态通知的订阅者。

2:我们发现这个和事件委托很像,也是定义一个委托,然后在定义一个事件,当状态发生改变的时候触发事件。下面看看编码

A:主题

/// <summary>
    /// 委托/事件实现主题
    /// </summary>
    public class SubjectEventHandler
    {
        //定义一个发送信息的委托
        public delegate void SendMessage(string str);
        //定义一个事件
        public event SendMessage SendTest;        
        /// <summary>
        /// 公布信息
        /// </summary>
        public string PublishInfo { get; set; }
        /// <summary>
        /// 发送信息
        /// </summary>
        public void Notify()
        {            
            if (SendTest!=null)
            {
                SendTest(PublishInfo);
            }
        }
    }

 B:得到信息后的操作

/// <summary>
    /// 响应事件后的操作
    /// </summary>
    public class ObserverEventHandler {
        public void Display(string str)
        {
            Console.WriteLine(str);
        }
    }

C:触发事件

SubjectEventHandler subjectEvent = new SubjectEventHandler();
            subjectEvent.PublishInfo = "实施2.5天假期制";
            ObserverEventHandler observerEvent = new ObserverEventHandler();            
            subjectEvent.SendTest += new SubjectEventHandler.SendMessage(observerEvent.Display);
            subjectEvent.Notify();

D:显示结果

 

3:在前面我们说过action也是用过表示委托的下面我们来看看action的操作

A:定义主题

/// <summary>
    /// 委托/事件实现主题
    /// </summary>
    public class SubjectEventHandler
    {
        public Action<string> SendAction; 
        /// <summary>
        /// 公布信息
        /// </summary>
        public string PublishInfo { get; set; }
        /// <summary>
        /// 发送信息
        /// </summary>
        public void Notify() {
            if (SendAction != null) {
                SendAction(PublishInfo);
            }
        }

B:

/// <summary>
    /// 响应事件后的操作
    /// </summary>
    public class ObserverEventHandler {
        public void Display(string str)
        {
            Console.WriteLine(str);
        }
    }

C:响应

    SubjectEventHandler subjectEvent = new SubjectEventHandler();
            subjectEvent.PublishInfo = "实施2.5天假期制";
            ObserverEventHandler observerEvent = new ObserverEventHandler();
            Action<string> action = observerEvent.Display;
            subjectEvent.SendAction = action;    
            subjectEvent.Notify();

同样实现了2中的效果

总结:个人觉得如果项目较大,而且偏向于有用户管理信息,用观察者模式。如果是比较小的项目或者只是触发一下事件就可以搞定可以使用事件委托。比喻我们要获取数据库某一个表中更新的数量,我们就不必每一次就去读取数据库,而是缓存中读取,但是缺点就是没有达到及时性,那么现在我们就可以用委托,每次更新一条数据那么就触发一次事件去数据库读取来更新缓存即可


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2020 CODEPRJ.COM