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

    观察者模式

    前言:最近花心思学习了一下设计模式,总体感觉设计模式主要是给我们提供解决问题的一种思路,是自己的代码可重用性高,保证代码的可靠性,设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
    首先我们通过一个故事来进行探讨:在曾经的一段时间里,我们的股市是非常火爆的,几乎接近了全名炒股的程度,张三(化名)经常会在上班的时候关注股市的信息,但总是会担心老板出现在自己的身后,这样总归是不太好的。在这个时候,张三想到了一个办法,在它的公司有一个前台的秘书,平常没事的时候经常找她聊聊天,关系也是挺不错的。这时候他就请前台的秘书(小童)请她帮忙,如果老板的时候让她提前打个招呼。这样就不会怕发现了。

    大家通过上面的故事:这个事情就是一个典型的观察者模式。

    定义:

    观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生改变的时候,会通知所有的观察者对象,使他们能够自动的进行更新。

     我们先给出图形方便大家的理解,如下:

    我们首先定义抽象通知类接口,通过我们的开放-封闭原则和依赖倒转原则,我们应该让程序都依赖于抽象,而不是相互依赖。我们选择了定义抽象通知类接口,代码如下:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 观察者模式
    {
        /// <summary>
        /// 抽象通知者接口
        /// </summary>
        interface Subject
        {
            /// <summary>
            /// 增加监听
            /// </summary>
            /// <param name="observer"></param>
            void Attach(Observer observer);
            /// <summary>
            /// 删除监听
            /// </summary>
            /// <param name="observer"></param>
            void Detach(Observer observer);
            /// <summary>
            /// 发送通知
            /// </summary>
            void Notify();
            /// <summary>
            /// 前台的状态
            /// </summary>
            string SubjectState { get; set; }
        }
    }

     


    那么接下来该定义抽象通知者的实现类了,我们继承的接口必须要实现里面全部的方法。全部代码的实现如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 观察者模式
    {
        /// <summary>
        /// 前台通知者类
        /// </summary>
        class FrontDesk : Subject
        {
            //同事列表
            private IList<Observer> observers = new List<Observer>();
            //行动
            private string action;
    
            /// <summary>
            /// 前台通过电话 所说的话或者是所做的事情
            /// </summary>
            public string SubjectState
            {
                get { return action; }
                set { action = value; }
            }
    
            /// <summary>
            /// 增加观察者
            /// </summary>
            /// <param name="observer">观察者</param>
            public void Attach(Observer observer)
            {
                observers.Add(observer);
            }
    
            /// <summary>
            /// 减少观察者
            /// </summary>
            /// <param name="observer">观察者</param>
            public void Detach(Observer observer)
            {
                observers.Remove(observer);
            }
    
            /// <summary>
            /// 发出通知
            /// </summary>
            public void Notify()
            {
                foreach (var o in observers)
                {
                    o.Update();
                }
            }
    
        }
    }

    好的我们的抽象的通知者已经定义好了,接下来我们定义抽象的观察者,我们各个的观察者都需要一个更新自身的状态的方法.代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 观察者模式
    {
        /// <summary>
        /// 抽象观察者
        /// </summary>
        abstract class Observer
        {
    
            //员工名字
            protected string name;
            //通知者的定义
            protected Subject sub;
    
            /// <summary>
            /// 构造函数进行初始化赋值操作
            /// </summary>
            /// <param name="name">名字</param>
            /// <param name="sub">通知者</param>
            public Observer(string name, Subject sub)
            {
                this.name = name;
                this.sub = sub;
            }
    
            /// <summary>
            /// 更新自身的状态
            /// </summary>
            public abstract void Update();
    
        }
    }

    接下来我们定义看股票观察者看NBA观察者并分别继承抽象观察者类,详细代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 观察者模式
    {
        /// <summary>
        /// 实体类:看股票的同事
        /// </summary>
        class StockObserver : Observer
        {
    
            /// <summary>
            /// 继承父类的构造函数
            /// </summary>
            /// <param name="name">名字</param>
            /// <param name="sub">通知者</param>
            public StockObserver(string name, Subject sub) : base(name, sub)
            {
    
            }
    
            /// <summary>
            /// 自身的状态的改变
            /// </summary>
            public override void Update()
            {
                Console.WriteLine("{0},{1},关闭股票行情,继续工作", sub.SubjectState, name);
            }
    
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 观察者模式
    {
        class LookNBAObserver : Observer
        {
    
            /// <summary>
            /// 继承的构造函数
            /// </summary>
            /// <param name="name"></param>
            /// <param name="sub"></param>
            public LookNBAObserver(string name, Subject sub) : base(name, sub) { }
    
            /// <summary>
            /// 改变自身的状态
            /// </summary>
            public override void Update()
            {
                Console.WriteLine("{0},{1},关闭NBA,继续工作", sub.SubjectState, name);
            }
    
        }
    }

    前台的调用的代码,详细代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 观察者模式
    {
        class Program
        {
            static void Main(string[] args)
            {
                //前台花花
                FrontDesk frontDesk = new FrontDesk();
                //看屁股(哈哈哈)的同事
                StockObserver stockObserver = new StockObserver("张雷", frontDesk);
                //看NBA的同事
                LookNBAObserver lookNbaObserver = new LookNBAObserver("骚鹏", frontDesk);
                //增加观察者
                frontDesk.Attach(stockObserver);
                frontDesk.Attach(lookNbaObserver);
                //花花发送消息,老板回来了
                frontDesk.SubjectState = "老板回来了";
                //减少观察者,这时候我不想通知张雷了,等着被老板抓吧,哈哈。
                frontDesk.Detach(stockObserver);
                //发出消息
                frontDesk.Notify();
                Console.ReadKey();
            }
        }
    }

    截图显示:

    观察者模式的特点

    我们接下来需要思考一个问题:用观察者模式的动机的什么呢?

    将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而是各类紧密耦合,这样会给维护,扩展和重用带来不便。

    我们什么使用使用观察者模式呢:当一个对象的改变需要同时的改变其他的对象的时候。

    其实当我们的通知者发出消息的时候,并不知道谁是他的观察者,也就是说,具体观察者是谁,他根本不需要知道是谁。而任何一个观察者也不知道也不需要知道其他的观察者的存在。

    总体来说:观察者所做的工作其实是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不影响到另一边的变化。

    观察者模式的不足

    尽管我们用了依赖倒转原则,但是抽象通知者还是依赖于抽象观察者,也就是说,万一没有了抽象观察者这样的接口的实现,这边的功能就实现不了了。

    我们接下来的改造:我们只需要在通知者中广播一个方法,至于是谁关注他不管,如果观察者对这条信息感兴趣就关注,不感兴趣就不关注。

    事件委托实现观察者模式(推荐使用)

    定义抽象通知者接口,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托与事件的方式实现观察者模式
    {
        interface Subject
        {
            //发送通知
            void Notify();
            //前台的状态
            string SubjectState { get; set; }
        }
    }


    定义前台类实现接口,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Eventing.Reader;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托与事件的方式实现观察者模式
    {
        //委托的声明
        delegate void EventHandler();
        /// <summary>
        /// 前台通知者
        /// </summary>
        class FrontDesk : Subject
        {
    
            //事件的声明
            public static event EventHandler Update;
    
            /// <summary>
            /// 前台的状态 所说的话或者所做的事情
            /// </summary>
            private string _subjectState;
            public string SubjectState
            {
                get { return _subjectState; }
                set { _subjectState = value; }
            }
    
            /// <summary>
            /// 发送消息
            /// </summary>
            public void Notify()
            {
                Update();
            }
    
        }
    }

    定义抽象观察者,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托与事件的方式实现观察者模式
    {
        abstract class Observer
        {
            //名字
            protected string name;
            //对通知者的引用
            protected Subject sub;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="name">名字</param>
            /// <param name="sub">通知者</param>
            public Observer(string name, Subject sub)
            {
                this.name = name;
                this.sub = sub;
            }
    
            /// <summary>
            /// 更新自身的状态
            /// </summary>
            public abstract void Update();
        }
    }

    观察者的实现类,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托与事件的方式实现观察者模式
    {
        class StockObserver : Observer
        {
            public StockObserver(string name, Subject sub) : base(name, sub)
            {
                //感兴趣进行关注,进行事件的注册
                FrontDesk.Update += Update;
            }
            /// <summary>
            /// 重写父类的方法,更新自己行为的方法
            /// </summary>
            public override void Update()
            {
                Console.WriteLine("{0} {1},关闭股票行情,继续工作", sub.SubjectState, name);
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托与事件的方式实现观察者模式
    {
        class NBAObserver : Observer
        {
            public NBAObserver(string name, Subject sub) : base(name, sub)
            {
                //事件的注册
                FrontDesk.Update += Update;
            }
    
            public override void Update()
            {
                Console.WriteLine("{0} {1},关闭NBA直播,继续工作", sub.SubjectState, name);
            }
        }
    }

    客户端代码的调用,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托与事件的方式实现观察者模式
    {
        class Program
        {
            static void Main(string[] args)
            {
                //前台花花
                FrontDesk huahua = new FrontDesk();
                //看股票的同事
                new StockObserver("张三", huahua);
                //看NBA直播的同事
                new NBAObserver("李四", huahua);
                huahua.SubjectState = "老板来了";
                //消息的发送
                huahua.Notify();
                Console.ReadKey();
            }
        }
    }

    调试结果截图如下:

    这样的话委托和事件的方式很好的实现了观察者模式!!好的我们的观察者模式就讲解完了,大家有什么问题和建议请大家积极的发言,明天就是10.24,程序员节快乐。

     

  • 相关阅读:
    iOS开发网络篇—GET请求和POST请求
    iOS开发网络篇—HTTP协议
    iOS开发网络篇—搭建本地服务器
    iOS开发网络篇—网络编程基础
    编程生涯
    使用NSURLSession实现断点续传
    定义设置颜色的RGB值的宏
    IB_DESIGNABLE的使用
    java文件和目录的增删复制
    Android离线语音识别(PocketSphinx)
  • 原文地址:https://www.cnblogs.com/MoRanQianXiao/p/7719810.html
Copyright © 2011-2022 走看看