设计模式之观察者模式

        相信各位在应该都有过在上班期间做一些和工作无关的事情吧(比如看球赛、看小说、炒股等(偷笑)),大多数公司是不允许职员上班期间做一些和工作无关的事情的,那么我们怎么在上班期间炒股而且不会被上级发现呢?(只是举个例子,本人没在工作期间炒股啊,上级的工位就在旁边(不敢做其他事情))如果能有个人在上级来之前就通知我们一下,这样我们就不会被发现了。

        基于此示例,我们来认识一下新的设计模式——观察者模式。什么是观察者模式呢?它又叫做发布-订阅模式,它定义了一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

        那么我们就根据上面的例子来认识一下什么是观察者模式。

        Talk is cheap. Show me the code!

abstract class Observer
    {
        private string _name;
        public string name { get { return _name; } set { _name = value; } }
        private Subject _subject;
        public Subject subject { get { return _subject; } set { _subject = value; } }
        public Observer(string name, Subject sub)
        {
            _name = name;
            _subject = sub;
        }

        abstract public void Update();
    }

    interface Subject
    {
        void Attach(Observer obs);
        void Detach(Observer obs);

        void Notify();

        string SubjectState { get; set; }
    }

    class Secretary : Subject
    {
        private string action;
        List<Observer> observers = new List<Observer>();
        public string SubjectState { get { return action; } set { action = value; } }

        public void Attach(Observer obs)
        {
            observers.Add(obs);
        }

        public void Detach(Observer obs)
        {
            observers.Remove(obs);
        }

        public void Notify()
        {
            foreach (var item in observers)
            {
                item.Update();
            }
        }
    }

    class StockObserver : Observer
    {
        public StockObserver(string name, Subject sub):base(name, sub)
        {

        }
        public override void Update()
        {
            Console.WriteLine("{0},{1}快把股票关了,继续工作", name, subject.SubjectState);
        }
    }

        首先我们定义了一个一个抽象接口Observer,来充当员工,里面有员工的姓名name以及谁要通知员工的对象Subject,并且还定义了抽象方法Update作为员工的行为;其次我们定义了负责通知的接口Subject,这个用来规范通知的行为;最后我们定义了一个秘书类Secretary并实现Subject接口,这样秘书类就有了通知的功能,同时我们也定义了上班期间炒股的员工StockObserver并使其继承Observer,方便我们后续统一管理。

        接下来我们来看一下使用示例:

internal class Program
        {
            static void Main(string[] args)
            {
                Secretary secretary = new Secretary();
                secretary.Attach(new StockObserver("张三", secretary));
                secretary.Attach(new StockObserver("李四", secretary));

                secretary.SubjectState = "老板回来了";
                secretary.Notify();
                Console.ReadKey();
            }
        }

        首先呢我们创建了一个秘书类的对象secretary,然后利用秘书类中添加要通知职员的方法来添加两位职员张三、李四,并且指定了通知这两位员工的人是我们刚刚实例化出来的秘书类对象;然后我们的秘书小姐姐发现老板回来了,便将自己切换成“老板回来了”的状态,一边和老板打招呼一边调用通知接口Notify,来通知张三和李四两位员工;最后两位员工收到通知后便可以提前营造好上班的氛围了。

        以上就是观察者模式的使用示例,那么我们在什么场景中会使用到这个模式呢?我们不想要为了达到某一功能而去同时维护不同的类(如有炒股的,有玩手机的,有看电视的等等,这样使用的时候就得实例化很多类型的员工对象,发现老板来了之后就得挨个去调用其内部的方法,很麻烦),这样会导致类中的耦合性很高,而且对于扩展和重复使用都很不方便。

        像上面说的,有的员工是在炒股,有的员工是在睡觉、玩手机,其内部方法肯定是不一样的呀,不能通知炒股的人不要睡觉了,睡觉的人不要炒股了,这就乱了呀,如果我们在抽象类中定义了炒股的行为、睡觉的行为等等,那这每增加一个摸鱼的行为所有继承员工类不都得实现吗?那多麻烦呀!鉴于此,我们可以给观察者模式改造一下,将通知的行为可以更方便的处理。那是什么方式呢?答案就是——delegate:事件委托。下面我们来看一下如何利用委托来优化观察者模式。

    class Secretary : Subject
    {
        private string action;
        List<Observer> observers = new List<Observer>();
        public string SubjectState { get { return action; } set { action = value; } }

        public void Attach(Observer obs)
        {
            observers.Add(obs);
        }

        public void Detach(Observer obs)
        {
            observers.Remove(obs);
        }

        public void Notify()
        {
            foreach (var item in observers)
            {
                item.Update();
            }

            Update();
        }

        public delegate void EventHandler();
        public event EventHandler Update;
    }

    class NBAObserver
    {
        private string name;
        private Subject sub;

        public NBAObserver(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        public void CloseNBA()
        {
            Console.WriteLine("{0},{1}关闭NBA直播,继续工作。", sub.SubjectState, name);
        }
    }

    class SleepObserver
    {
        private Subject subject;
        private string name;
        public SleepObserver(string name, Subject subject)
        {
            this.subject = subject;
            this.name = name;
        }

        public void Wakeup()
        {
            Console.WriteLine("{0},{1}醒来,继续工作。", subject.SubjectState, name);
        }
    }

        我们在秘书类中声明了一个委托类型,并规定其只能接收无返回值无参的方法,并且在通知方法中直接调用该委托事件Update;最后我们分别定义了两个上班摸鱼的员工,一个在看NBA直播,一个在偷偷睡觉。使用方法如下:

internal class Program
        {
            static void Main(string[] args)
            {
                Secretary secretary = new Secretary();
                NBAObserver watchNBA = new NBAObserver("张三", secretary);
                SleepObserver sleepObserver = new SleepObserver("李四", secretary);

                secretary.Update += watchNBA.CloseNBA;
                secretary.Update += sleepObserver.Wakeup;

                secretary.SubjectState = "老板回来了";
                secretary.Notify();
                Console.ReadKey();
            }
        }

        和上一个示例有所不同的是,这次我们实例化秘书对象以及两个摸鱼的员工的对象之后,不再是通过秘书类中的Attach方法来添加员工对象,而是采用委托的形式将员工类中老板回来之后的行为告诉秘书,这样秘书就会通过Update委托来告诉看NBA直播的员工不要看了,睡觉的员工也该醒了,要继续上班了,而且通过委托的+=方法,可以规定先后顺序(比如老板最先能看到睡觉的员工,那么就先让Update += 睡觉的员工里叫醒的方法,然后再+=其他方法,这样秘书对象就知道要先叫醒睡觉的员工,然后再去通知其他员工了,这也是事件的一个特点)。

        好了,以上就是观察者模式的使用示例以及优化部分,本篇幅较其他偏长,内容较多,但涉及的都不是很深的知识,相信各位看官应该都可以理解并学会如何使用。最后,thanks for reading!!!!

注:本人的设计模式系列是根据大话设计模式一书中的内容,加以自身总结说明,一方面想多锻炼自身的表达能力,另一方面希望能够提升自身的编程能力及代码架构水平。若是能让更多的人通过我的文章来明白该设计模式的作用、应用场景及独立设计出来,当然也是对我个人表达能力的提升及掌握程度的认可。最后再次说明,本文内容来自大话设计模式一书,我只是写出来并加以总结希望达到熟练掌握的程度。如果你通过本文搞懂了,那么50%归功于此书,49%归功于你自己,1%为本人(脸都不要了)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值