zoukankan      html  css  js  c++  java
  • 观察者模式(Observer Pattern)

    (1)应用:
    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己
    (2)角色:
        * 抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
        * 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
        * 具体主题(ConcreteSubject)角色:将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。
        * 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
    (.NET中提供了Delegate与Event机制,我们可以利用这种机制简化Observer模式。)
    (3)故事:
    此时,玉皇大帝和一群神仙已来到南天门观战,只见二郎神率领梅山六兄弟围着孙悟空好一阵穷追猛打。
    太上老君说:“让我来助二郎神一功。”说着捋起衣袖,从左胳膊上取下一只“金钢套”,
    照准猴王的脑袋扔了下去。猴王苦战之中,来不及躲闪,被“金钢套”打中了天灵,跌了一跤。
    正待爬将起来就跑,被二郎神豢养的哮天犬赶上来,一口咬住了腿肚子。
    二郎神和梅山六兄弟一拥而上,终于捉住了这个不可一世的妖猴。
    (4)分析:
    观察者模式定义了一种一(猴子)对多(观战团成员)的依赖关系,让多个观察者对象(观战团成员)同时监听某一个主题对象(猴子)。这个主题对象(猴子)在状态上发生变化时,会通知所有观察者对象(观战团成员工),使它们能够自动更新自己
    (5)实现
    using System;
    using System.Collections.Generic;

    public delegate void 委托通知观察者(状态持有者 观察对象);
    public class 状态持有者
    {
        /// <summary>
        /// 私有状态
        /// </summary>
        private string _状态;
        /// <summary>
        /// 只读
        /// </summary>
        public string 状态 { get { return _状态; } }
        public 状态持有者()
        {
            _状态 = "正在战斗";
        }
        /// <summary>
        /// 战斗过程
        /// </summary>
        public void 战斗过程开始()
        {
            //通知观战团猴子的被始状态
            设置状态(_状态);
            //变更状态,也会引发通知
            Console.WriteLine("二郎神率领梅山六兄弟围着孙悟空好一阵穷追猛打");
            设置状态("被穷追猛打");
        }
        //为了示例,让你们直接修改我的状态好了
        //其实你扔金钢套,不一定能打中我
        //另外我也不怕狗
        public void 设置状态(string 状态)
        {
            _状态 = 状态;
            if (通知观察者 != null)
            {
                Console.WriteLine("现在还有{0}个观察者在偷偷看我" , 通知观察者.GetInvocationList().Length);
                通知观察者(this);
            }
        }
        public event 委托通知观察者 通知观察者;
    }


    /// <summary>
    /// 抽象观察者,除了玉帝,其它人不允许你干看着
    ///对了玉帝也不行,你不出力也要喊两嗓子,以示你是一个观察者
    /// </summary>
    public inte***ce 观察者
    {
        void 行动(状态持有者 观察对象);
    }

    /// <summary>
    /// 对不起,我只会说不会做
    /// </summary>
    public class 玉帝 : 观察者
    {
        public void 行动(状态持有者 观察对象)
        {
            Console.WriteLine("玉帝:我看到猴子" + 观察对象.状态);
        }
    }
    public class 太上老君 : 观察者
    {
        public void 行动(状态持有者 观察对象)
        {
            if (观察对象.状态 == "正在战斗")
            {
                Console.WriteLine("太上老君:我在等待时机");
            }
            //该出手时就出手呀
            else if (观察对象.状态 == "被穷追猛打")
            {
                Console.WriteLine("太上老君:我扔下金钢套,打中了猴子");
                观察对象.通知观察者 -= new 委托通知观察者(行动);
                Console.WriteLine("太上老君:任务完成,退出观察者行列");
                观察对象.设置状态("跌了一跤");
                
            }

        }
    }
    /// <summary>
    /// 其中的一名观察者,为了等猴子跌一跤
    /// </summary>
    public class 哮天犬 : 观察者
    {
        public void 行动(状态持有者 观察对象)
        {
            if (观察对象.状态 == "跌了一跤")
            {
                Console.WriteLine("哮天犬赶上来,一口咬住了腿肚子");
                观察对象.通知观察者 -= new 委托通知观察者(行动);
                观察对象.设置状态("咬住了腿肚子");
            }
        }
    }

    /// <summary>
    ///作用与哮天犬同
    ///为了讲完这个故事
    /// </summary>
    public class 二郎神和梅山六兄弟 : 观察者
    {
        public void 行动(状态持有者 观察对象)
        {
            if (观察对象.状态 == "咬住了腿肚子")
            {
                Console.WriteLine("二郎神和梅山六兄弟一拥而上,终于捉住了这个不可一世的妖猴");
                观察对象.通知观察者 -= new 委托通知观察者(行动);
                观察对象.设置状态("被捉住了");
            }
        }
    }

    public class MyClass
    {
        public static void Main()
        {
            //天庭观战团有四名成员
            观察者[] 天庭观战团 = new 观察者[]{
                new 玉帝(),
                new 太上老君(),
                new 哮天犬(),
                new 二郎神和梅山六兄弟()
                };
            //实例化状态持有者,这儿就是孙悟空
            状态持有者 孙悟空 = new 状态持有者();
            //孙悟空要知会所有对自己状态感兴趣的成员
            //有点笨,你不通知它们不就好了
            foreach (观察者 实例化的观察者 in 天庭观战团)
            {
                孙悟空.通知观察者 += new 委托通知观察者(实例化的观察者.行动);
            }
            //开始打斗
            孙悟空.战斗过程开始();
            
            Console.Read();
        }
    }
    (6)结果
    现在还有4个观察者在偷偷看我
    玉帝:我看到猴子正在战斗
    太上老君:我在等待时机
    二郎神率领梅山六兄弟围着孙悟空好一阵穷追猛打
    现在还有4个观察者在偷偷看我
    玉帝:我看到猴子被穷追猛打
    太上老君:我扔下金钢套,打中了猴子
    太上老君:任务完成,退出观察者行列
    现在还有3个观察者在偷偷看我
    玉帝:我看到猴子跌了一跤
    哮天犬赶上来,一口咬住了腿肚子
    现在还有2个观察者在偷偷看我
    玉帝:我看到猴子咬住了腿肚子
    二郎神和梅山六兄弟一拥而上,终于捉住了这个不可一世的妖猴
    现在还有1个观察者在偷偷看我
    玉帝:我看到猴子被捉住了
  • 相关阅读:
    线程池类型场景和问题
    react Antdesign Select添加全选功能
    API与ESB 、ServiceMesh、微服务究竟关系如何?
    RabbitMQ四种Exchange类型
    RabbitMq安装
    kafka 部署
    共享文件夹重启后每次都要输入密码
    algorithm 12 partial_sort_copy
    algorithm 11 nth_element
    algorithm 11 none_of
  • 原文地址:https://www.cnblogs.com/SALIN/p/1260159.html
Copyright © 2011-2022 走看看