观察者模式

前言

有种发邮件,一发多的感觉,发出去的是同样的信息,只不过接收到的人不一样了。

观察者模式

英文:Observer
又名:发布-订阅(Publish/Subscribe)模式

what:

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

结构图

观察者

Subject类:
抽象通知者:实现→一般用一个抽象类或者一个接口实现,
它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
增加:attach(observers.add(observer)
移除:detach(observers.remove(observer)

Observer类:
抽象观察者,实现→一般用一个抽象类或者一个接口实现
为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。更新接口通常包含一个Update()方法,这个方法叫做更新方法

ConcreteSubject类:
具体主题或者具体通知者,实现→具体主题角色通常用一个具体子类实现。
将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。

ConcreteObserver类:
具体观察者,实现→通常用一个具体子类实现。
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。

场景

由于晚上睡觉太晚,所以上课的时候想打个盹,这时就会告诉同桌:“嘿!老师来了叫我一声!”然后同桌非常有底气的就回了我一句:“木有问题!”
然后老师过来我这里了:“你们俩!站起来!怎么都睡着了?“
额。。。说好的叫我呢?
这个时候,观察者模式就来了,不能只依赖同桌这个具体通知者,如果有一个类来管理这个,就不会有都被逮住了,还闻不到危险已到来的气息~

应用

当一个对象的改变需要同时改变其他对象的时候。
而且它不知道具体有多少对象有待改变时
观察者模式所做的工作就是解除耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响到另一边的变化。
它是依赖倒转原则的最佳体现。

代码展示:

抽象通知者:

interface Subject        //通知者接口
    {
        void Attach(Observer observer);
        void Detach(Observer observer);
        void Notify();
        string SubjuctState
        {
            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 SubjuctState
        {
            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 TV:Observer 
    {
        //将具体通知者boss改为抽象通知者subject
        public TV(string name, Subject sub): base(name, sub)
        { 
        }

        public override void Update()
        {
                                                //将具体通知者状态改成抽象通知者状态
            Console.WriteLine("{0}{1},快点关上电视,继续工作,否则扣工资!扣工资!!",sub.SubjuctState ,name);
        }
    }

客户端代码:

 class Program
    {
        static void Main(string[] args)
        {
            //老板
            Boss monkey = new Boss();

            //员工
            TV mm = new TV("范冰冰", monkey);

            monkey.Attach(mm);

            //老板回来
            monkey.SubjuctState = "我回来啦!";

            //发出通知
            monkey.Notify();

            Console.Read();
        }
    }

效果图:

观察者

事件委托

what

委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的”类“,委托的实例将代表一个具体的函数。
一个委托可以搭载多个方法,所有方法被一次唤起。它可以使得委托对象所搭载的方法并不需要属于同一个类。

委托的前提:
委托对象所搭载的所有方法必须具有相同的原型和形式,也就是拥有相同的参数列表和返回值类型。
先有观察者模式,再有的委托事件技术。

情景

”mm,我手机丢了,班里的手机号都没有了,你能把班级同学的手机号抄一份给我吗?“
”这么多人,抄起来,容易错,我给同学群发一条消息,通知他们把你的号码更新了把。“
”好的,你一定要记得发给**,##,&&哦。“
”我才不管呢,凡是在我手机里的,我都会循环遍历一遍,群发给他们的。“
”好的,你就循环遍历一下,这事就委托给你咯。“

代码展现:

委托引用了方法,看起来又简单了很多。

通知者接口:

 interface Subject   //通知者接口
    {
        void Notify();
        string SubjectState
        {
            get;
            set;
        }
    }

具体通知者:

 //声明一个委托,名称为EventHandler(事件处理程序),无参数,无返回值
    delegate void EventHandler();   

    class Boss:Subject 
    {
        public event EventHandler Update;  //声明委托事件,名称为Update(更新)
        private string action;

        public void Notify()
        {
            Update();        //在访问通知方法时,调用Update
        }

        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }

观察者接口:

interface Observer       //观察者接口
    {
        void Update();
    }

具体观察者:

class TV      //具体观察者1
    {
        private string name;
        private Subject sub;
        public TV (string name, Subject sub)  
        {
            this.name = name;
            this.sub = sub;
        }

        //关闭电视

        public void CloseTVtt()     //更新名改为关闭
        {
            Console.WriteLine("{0}{1}关闭电视,抓紧工作,否则扣工资!",sub.SubjectState ,name );
        }
    }

    //同上↑----具体观察者2
    class Game
    {
        private string name;
        private Subject sub;
        public Game(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        //关闭电视

        public void CloseGamett()
        {
            Console.WriteLine("{0}{1}关闭游戏,抓紧工作,否则扣工资!", sub.SubjectState, name);
        }
    }

客户端代码:

 class Program
    {
        static void Main(string[] args)
        {
            //老板
            Boss mongkey = new Boss();

            //员工
            TV mm = new TV("张三",mongkey);
            Game yy = new Game ("李四",mongkey );

            //将关闭方法挂钩到“老板”的更新上,将两不同类的不同方法委托给老板类的更新了。

            mongkey.Update += new EventHandler(mm.CloseTVtt);
            mongkey.Update += new EventHandler(yy.CloseGamett);

            mongkey.SubjectState = "我回来啦!";

            mongkey.Notify();

            Console.Read();
        }
    }

效果图:

这里写图片描述

后记

搞怪一下~
观察者前期+后期委托共有10个
看了效果图后,突然感觉自己再多敲几个类,都是值得的!!!哈
3

学习中一定要给自己找些乐趣,不然就太枯燥了~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值