设计模式——剖析观察者模式

来源:互联网 发布:公司网络拓扑 编辑:程序博客网 时间:2024/04/28 20:12
 

观察者模式又叫做发布——订阅模式。

 

1、定义

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

 

    根据定义我们可以看出观察者模式有两个对象,而且必须都存在:观察者和被观察者。观察者是具体执行操作的对象,有多个;被观察者如果发生变化,则会通知观察者去执行相应的操作。此外还可以看出,当一个对象的改变需要同时通知其他对象的时候,而且它不知道具体有多少对象需要通知的时候,需要通知的对象能够动态地增加。

        

    在此种模式中,一个目标管理所有依赖于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。

 

2、结构图

 

    通过上图可以看出观察者模式有四种角色,抽象观察者角色,具体观察者角色,抽象主题角色,具体主题角色。主题与观察者都是用接口,观察者利用主题接口向主题注册;而主题利用观察者接口通知观察者。从而让两者之间运行正常,同时又具有松耦合的特点。所以,观察者模式是针对接口编程,不针对实现编程。体现了依赖倒转原则。

 

3、举例

    我们用一个例子来说明

    魏管姹在看股票,易管查在看NBA直播,为了不让老板发现,他们就请前台童子喆来通知老板到没到,一天,老板带着童子喆去办公室拿东西,童子喆没有办法通知了,魏管姹被老板发现了。这时,老板可以作为一个通知者,结构图和代码如下。

     

结构图

 

代码实现

 

  //通知者接口    interface Subject    {        void Attach(Observer observer);        void Detach(Observer observer);        void Notify();        string SubjectState        {            get;            set;        }    }    //老板类实现接口    class Boss : Subject    {          //同事列表        private IList<Observer> observers = new List<Observer>();        private string action;        //增加观察者        public void Attach(Observer observer)        {            observers.Add(observer);        }        //减少观察者        public void Detach(Observer observer)        {            observers.Remove(observer);        }        //通知观察者        public void Notify()        {            foreach (Observer o in observers)                o.Update();        }        //老板状态        public string SubjectState        {            get { return action; }            set { action = value; }        }    }

 

//抽象观察者    abstract class Observer    {        protected string name;        protected Subject sub;        public Observer(string name, Subject sub)        {            this.name = name;            this.sub = sub;        }        public abstract void Update();    }    //看股票的同事    class StockObserver : Observer    {        public StockObserver(string name, Subject sub)            : base(name, sub)        { }        //根据主题对象行为更新自己        public override void Update()        {            Console.WriteLine("{0}{1}关闭股票行情,继续工作!", sub.SubjectState, name);        }    }    //看NBA的同事    class NBAObserver : Observer    {        public NBAObserver(string name, Subject sub)            : base(name, sub)        { }               //根据主题对象的行为更新自己        public override void Update()        {            Console.WriteLine("{0}{1}关闭NBA,继续工作!",sub.SubjectState ,name);        }    }

 

客户端

class Program    {        static void Main(string[] args)        {            //老板胡汉三            Boss huhansan = new Boss();            //两个同事            StockObserver tongshi1 = new StockObserver("魏管姹", huhansan);            NBAObserver tongshi2 = new NBAObserver("易管查", huhansan);                        //增加同事            huhansan.Attach(tongshi1);            huhansan.Attach(tongshi2);            //减少同事            huhansan.Detach(tongshi1);            //老板状态            huhansan.SubjectState = "我胡汉三回来了!";            //通知            huhansan.Notify();        }    }

 

4、事件委托

    

    委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。

使用委托的前提:委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值。

 

举例:还是上一个例子,用委托方法实现。

 

代码实现

 //通知者接口    interface Subject    {    void Notify();        string SubjectState        {        get;        set;        }    }    //声明一个委托,无参数,无返回值    delegate void EventHandler();    //老板类    class Boss:Subject    {    //声明一事件Update,类型为委托EventHandler     public event EventHandler Update;       //老板行为    private string action;        //通知时更新    public void Notify()    {      Update();    }                //老板状态        public string SubjectState        {        get{return action;}        set{action=value;}        }    }

 

     看股票同事和看NBA直播同事去掉父类,根据各自的不同更新各自动作

//看股票的同事    class StockObserver    {        private string name;        private Subject sub;        public StockObserver(string name, Subject sub)        {            this.name = name;            this.sub = sub;        }        //关闭股票行情        public void CloseStockMarket()        {            Console.WriteLine("{0}{1}关闭股票行情,继续工作!", sub.SubjectState, name);        }    }    //看NBA直播    class NBAObserver    {        private string name;        private Subject sub;        public NBAObserver(string name,Subject sub)        {        this.name=name;        this.sub=sub;        }        //关闭NBA直播        public void CloseNBADirectSeeding()        {        Console.WriteLine("{0}{1}关闭NBA,继续工作!",sub.SubjectState,name);        }    }

 

    客户端增加减少委托事件

class Program    {        static void Main(string[] args)        {            //老板            Boss huhansan=new Boss ();            //同事            StockObserver tongshi1=new StockObserver("魏管姹",huhansan);            NBAObserver tongshi2=new  NBAObserver ("易管查",huhansan);                        //增加委托            huhansan.Update+=new EventHandler (tongshi1.CloseStockMarket );            huhansan.Update+=new EventHandler (tongshi2.CloseNBADirectSeeding );            //老板状态            huhansan.SubjectState ="我胡汉三回来了!";            //通知            huhansan.Notify ();        }    }

  
 

5、两个例子区别   

    这两个例子实现的区别:通过委托实现的是把两个子类分开,去掉了父类,把各自的方法更新放在了自己类里面,声明了一个委托,把通知这个事件委托给老板,老板状态一更新,观察者的状态也就随着改变,只要增加一个观察者就增加一个委托事件。而观察者模式是通过具体观察者继承抽象观察者,抽象通知者依赖于抽象观察者。

   

 

6、总结

    通过观察者模式,把一对多对象之间的通知依赖关系变得更为松散,大大的提高程序的可维护性和可扩展性,也很好的符合了开放—封闭原则。

       

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 黑色裤子晒红了怎么办 黑色裤子泛红了怎么办 黑色裤子洗红了怎么办 新内衣穿了痒怎么办 灰色针织运动裤洗完发黄怎么办 皮衣买大了一号怎么办 紧身衣破了一个洞怎么办 紧身衣破了一个小洞怎么办 内衣肩带不带调整的怎么办 不正确佩戴胸罩导致下垂怎么办 增肌时期晚上饿怎么办 啤酒和可乐喝了怎么办 脸部毛孔堵塞不出汗怎么办 减肥运动完饿了怎么办 想减肥晚上饿了怎么办 孕妇喝不进去水怎么办 跑步喝多了水怎么办 衣柜门轮子坏了怎么办 穿瑜伽裤下边有缝怎么办 3岁宝宝比较内向怎么办 我想和我同学搞基怎么办 自己做的葡萄酒太甜怎么办 吉米学校想退款怎么办 汽车租赁公司不退押金怎么办 身材不好怎么办健身教练形象照 反祈祷式做不到怎么办 窦性心跳过缓怎么办 四维彩超查出胎儿心脏有问题怎么办 减脂肚子饿了怎么办 做瑜伽腰扭到了怎么办 出了汗怎么办活动反思 农村都是老人和孩子怎么办 瑜伽垫容易出现痕迹怎么办 37岁失业了该怎么办 45岁找什么工作怎么办 华为手机4g网速慢怎么办 解析软件包时出现问题怎么办 一字马不能下去髋摆不正怎么办 练轮瑜伽骆驼式腰疼怎么办 感昌咳嗽老不好怎么办 我感昌一直不好怎么办