观察者模式

介绍

定义

观察者模式又叫做发布-订阅模式,模型-视图模式。

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

理解

观察者模式完美的将观察者和被观察的对象分离开。举个常见的例子,前阵子由于总是突发性高烧去医院检查,肯定得排队哈,不能隔两分钟就去问大夫“轮到我了吗?”,而是坐在门口等候大夫的通知,大家都接收到一个名字的信号,叫谁谁去。在这其中,大夫手里的名单就是被观察者,每一个病人就是一个观察者。

结构图


举例实现

通知者接口
 //通知者接口
    interface Subject
    {
        void Attach(Observer observer);
        void Detach(Observer observer);
        void Notify();
        string SubjectState
        {
            get;
            set;
        }
    }
具体的通知者类
 //具体的通知者(病人名单)这只是其中一个通知的方法,也可以实现其他的方法,所有可以让此实现通知者接口
    class Roster: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 Patient:Observer
    {
        public Patient (string name,Subject sub):base(name ,sub )  //抽象通知者取代具体通知者Subject sub
        {

        }
        public override void Update()
        {
            Console.WriteLine("{0} {1}来病房进行检查!", sub.SubjectState, name);  //抽象通知者状态代替可能出现的具体通知状态,如病人名单
        }
    }
客户端代码:
static void Main(string[] args)
        {
            //金秀贤名字通知
            Roster mingdan= new Roster();


            //等待中的金秀贤
            Patient bingren1 = new Patient("金秀贤", mingdan);


           mingdan.Attach(bingren1);


            //通知到
            mingdan.SubjectState = "金秀贤同志!";
            //发出通知
           mingdan.Notify();
        }
通知病人也有通知不到的时候,或许没有在,也或者声音小,没有注意听。其实结果一样,代码如下
static void Main(string[] args)
        {
            //金秀贤名字通知
            Roster mingdan= new Roster();

            //等待中的金秀贤
            Patient bingren1 = new Patient("金秀贤", mingdan);
            //等待中的淑敏君
            Patient bingren2 = new Patient("淑敏君", mingdan);

           mingdan.Attach(bingren1);
           mingdan.Attach(bingren2);
           mingdan.Detach(bingren2);   //没有被通知到
            //通知到
            mingdan.SubjectState = "金秀贤同志!";
            //发出通知
           mingdan.Notify();
        }
    }

结果显示:


事件委托

委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的”类“,委托的实例将代表一个具体的函数
就如上边的例子,或许有的医院并没有那么正规,只是病房里没有病人了,就会叫外边的根据不同的病情进入病房,叫病人的方法也可以由好多种方法,为了处理这些方法的类,用到了委托。
代码如下:
声明一个委托,名称叫”EventHandler“,无参数,无返回值。
delegate void EventHandler();
类的区分:(在此只写了一个名单通知的类)
  class Roster : Subject
    {
        //声明一事件Update,类型为委托EventHandler
        public event EventHandler Update;   //声明一“EventHandler"的委托事件,名称叫Update

        private string action;
        
        //通知
        public void Notify()
        {
            Update();
        }
        //名单状态,看看叫到哪个名字了
        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }
客户端重要代码:
 //金秀贤名字通知
            Roster mingdan = new Roster();

            //等待中的金秀贤
            PatientHeadache bingren1 = new PatientHeadache("金秀贤", mingdan);
            //等待中的淑敏君
            PatientHaveFever bingren2 = new PatientHaveFever("淑敏君", mingdan);

            mingdan.Update += new EventHandler(bingren1.IntoHeadache);
            mingdan.Update += new EventHandler(bingren2.IntoHaveFever);
            //将看“头痛的病人”和看“发烧的病人”和“分别进入病房的方法”都挂钩到“名单”的“更新”上了,也就是将量不同类的不同方法委托给名单类的“更新”了
            //通知到
            mingdan.SubjectState = "病人名单通知:";
            //发出通知
            mingdan.Notify();
实现结果:

结果出来了,委托与事件的机制几乎消除了这两个模块之间的耦合,灵活性提高了很多。如果需要增加观察者,则只需要覆盖基类抽象方法及把观察目标传递给基类。委托和事件处理事情的能力真的是令人佩服啊!

好处总结

观察者模式最终所达到的效果就是实现了“高内聚,低耦合“,所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

posted on 2014-04-05 14:56  huohuoL  阅读(130)  评论(0编辑  收藏  举报

导航