观察者模式(Observer Pattern)

原创 2012年03月21日 23:05:44

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

Subject类:被观察对象
(1)它把所有对观察者的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,
可以增加和删除观测者对象。
ConcreteSubject类:具体的被观察对象
(1)将有关状态存入具体的观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知
Observer类:抽象观察者
(1)为所有具体观察者定义一个接口,在得到主题的通知时更新自己
ConcreteObserver:具体观察者
(1)实现抽象观察者角色所要求的更新接口,以便本身的状态与主题的状态想协调。

/// <summary>
    /// Suject类,可译为主题或抽象通知者、被观察对象,一般用一个抽象类或一个接口实现。
    /// </summary>
    public abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();

        /// <summary>
        /// 增加观察者
        /// </summary>
        /// <param name="observer"></param>
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        /// <summary>
        /// 移除观察者
        /// </summary>
        /// <param name="observer"></param>
        public void Detach(Observer observer)
        {
            if (observers.Contains(observer))
            {
                observers.Remove(observer);
            }
        }
        /// <summary>
        /// 通知观察者,更新所有的观察者
        /// </summary>
        public void Notify()
        {
            foreach (Observer observer in observers)
            {
                observer.Update();
            }
        }
    }

    /// <summary>
    /// ConcreteSubject类,具体的通知者,将有关状态存入具体观察者对象;在具体主题的内部
    /// 改变时,给所有登记过的观察者发出通知。
    /// </summary>
    public class ConcreteSubject:Subject
    {
        private string subjectState;

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

    /// <summary>
    /// Observer类,抽象观察者。一般用一个抽象类或接口实现。更新接口通常包含一个Update()的方法,
    /// 这个方法叫更新方法
    /// </summary>
    public abstract class Observer
    {
        public abstract void Update();
    }

    /// <summary>
    /// ConcreteObserver类,具体观察者,实现抽象观察者所提供的更新接口,以便使本身的状态与
    /// 通知者的状态向协调。具体观察者可以保存一个指向具体通知者对象的引用。
    /// </summary>
    public class ConcreteObserver : Observer
    {
        private string name;
        private string observerState;
        private ConcreteSubject subject;

        public ConcreteSubject Subject
        {
            get { return subject; }
            set { subject = value; }
        }

        public ConcreteObserver(ConcreteSubject subject, string name)
        {
            this.subject = subject;
            this.name = name;
        }

        public override void Update()
        {
            observerState = subject.SubjectState;
            Console.WriteLine("观察者{0}的状态是{1}",name,observerState);
        }

    }

 //客户端调用
    class Program
    {
        static void Main()
        {
            ConcreteSubject s = new ConcreteSubject();

            s.Attach(new ConcreteObserver(s, "X"));
            s.Attach(new ConcreteObserver(s, "Y"));

            s.SubjectState = "ABC";
            s.Notify();
        }
    }

实例:ATM取款
取款后,以邮件和短信方式通知取款人。

 

/// <summary>
    /// Observer类:抽象观察者,定义更新方法
    /// 依赖抽象观察者
    /// </summary>
    public interface IObserverAccount
    {
        void Update(Subject sueject);
    }

 

/// <summary>
    /// Subject类:抽象通知者类
    /// 依赖于抽象观察者,与具体的观察者无关
    /// </summary>
    public abstract class Subject
    {
        private IList<IObserverAccount> observers = new List<IObserverAccount>();

        private double _money;

        public double Money
        {
            get { return _money; }
            set { _money = value; }
        }

        public Subject(double money)
        {
            this._money = money;
        }

        public void AddObserver(IObserverAccount observer)
        {
            this.observers.Add(observer);
        }

        public void RemoveObserver(IObserverAccount observer)
        {
            if (observers.Contains(observer))
            {
                observers.Remove(observer);
            }

        }

        public void WithDraw()
        {
            foreach (IObserverAccount observer in observers)
            {
                observer.Update(this);
            }
        }
    }

 

/// <summary>
    /// 具体的通知者
    /// </summary>
    public class BankAccount:Subject
    {
        public BankAccount(double money)
            : base(money)
        {

        }
    }

 

/// <summary>
    /// 具体的观察者类
    /// </summary>
    public class Emailer:IObserverAccount
    {
        private string _emailer;

        public Emailer(string emailer)
        {
            this._emailer = emailer;
        }

        #region IObserverAccount 成员

        public void Update(Subject sueject)
        {
            Console.WriteLine("您于{0}在ATM机取款{1:C}",DateTime.Now,sueject.Money);
        }

        #endregion
    }

 

/// <summary>
    /// 具体观察者类
    /// </summary>
    public class Mobile:IObserverAccount
    {
        private string _phoneNumber;

        public Mobile(string phoneNumber)
        {
            this._phoneNumber = phoneNumber;
        }

        #region IObserverAccount 成员

        public void Update(Subject sueject)
        {
            Console.WriteLine("您于{0}在ATM机取款{1:C}", DateTime.Now, sueject.Money);
        }

        #endregion
    }

 

客户端引用

            Subject subject = new BankAccount(2000);
            subject.AddObserver(new Emailer("
wafe5566@163.com"));
            subject.AddObserver(new Mobile("13993999999"));
            subject.WithDraw();

 

推模式与拉模式(以上为推模式)
    在Observer模式中同样区分推模式和拉模式,我先简单的解释一下两者的区别:
 推模式是当有消息时,把消息信息以参数的形式传递(推)给所有观察者,
 而拉模式是当有消息时,通知消息的方法本身并不带任何的参数,是由观察者自己到主体对象那儿取回(拉)消息。
 我们先看看这种模式带来了什么好处:当有消息时,所有的观察者都会直接得到全部的消息,并进行相应的处理程序,
 与主体对象没什么关系,两者之间的关系是一种松散耦合。但是它也有缺陷,第一是所有的观察者得到的消息是一样的,
 也许有些信息对某个观察者来说根本就用不上,也就是观察者不能“按需所取”;
 第二,当通知消息的参数有变化时,所有的观察者对象都要变化。
 鉴于以上问题,拉模式就应运而生了,它是由观察者自己主动去取消息,需要什么信息,就可以取什么,
 不会像推模式那样得到所有的消息参数。

 

用事件和委托来实现Observer模式更加的简单和优雅,也是一种更好的解决方案。

 

//定义一个委托
    public delegate void NotifyEventHandler(object sender);

    public class ObserverByEvent
    {
        /// <summary>
        /// 通知者类
        /// </summary>
        public class Subject
        {
            public event NotifyEventHandler NotifyEvent;

            private double _money;

            public double Money
            {
                get { return _money; }
                set { _money = value; }
            }

            public Subject(double money)
            {
                this._money = money;
            }

            public void WithDraw()
            {
                OnNotifyChange();
            }
            public void OnNotifyChange()
            {
                //监听是否有事件
                if (NotifyEvent != null)
                {
                    NotifyEvent(this);
                }
            }
        }

        /// <summary>
        /// 具体的观察者类
        /// </summary>
        public class Emailer
        {
            private string _emailer;

            public Emailer(string emailer)
            {
                this._emailer = emailer;
            }

            public void Update(object obj)
            {
                if (obj is Subject)
                {
                    Subject subject = (Subject)obj;
                    Console.WriteLine("您于{0}在ATM机取款{1:C}", DateTime.Now, subject.Money);
                }
            }
        }

        public class Mobile
        {
            private string _phoneNum;

            public Mobile(string phoneNum)
            {
                this._phoneNum = phoneNum;
            }

            /// <summary>
            /// 定义一个和委托类型相同签名的方法
            /// </summary>
            /// <param name="obj"></param>
            public void Update(object obj)
            {
                if (obj is Subject)
                {
                    Subject subject = (Subject)obj;
                    Console.WriteLine("您于{0}在ATM机取款{1:C} RMB", DateTime.Now, subject.Money);
                }
            }
        }
    }

 

//委托事件方法
            ObserverByEvent.Subject subject2 = new ObserverByEvent.Subject(2000);
            subject2.NotifyEvent+=new NotifyEventHandler(new ObserverByEvent.Emailer("
wafe5566@163.com").Update);
            subject2.NotifyEvent+=new NotifyEventHandler(new ObserverByEvent.Mobile("13993997988").Update);
            subject2.WithDraw();

设计模式笔记——(三:观察者模式 Observer Pattern)

观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/...
  • xiaoyu_93
  • xiaoyu_93
  • 2016年11月18日 15:38
  • 822

设计模式总结之Observer Pattern(观察者模式)

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。...
  • cooldragon
  • cooldragon
  • 2016年08月11日 00:53
  • 853

设计模式 - 观察者模式(Observer Pattern) 详解

观察者模式(Observer Pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权...
  • u012515223
  • u012515223
  • 2014年05月22日 14:37
  • 2921

设计模式之观察者模式 (Observer Design Pattern)

一、什么是观察者模式观察者定义了一种一对多的依赖关系,当一个主题(Subject)对象状态发生变化时,所有依赖它的相关对象都会得到通知并且能够自动更新自己的状态,这些依赖的对象称之为观察者(Obser...
  • suifeng3051
  • suifeng3051
  • 2016年04月27日 19:32
  • 904

观察者模式(Observer Pattern)

设计原理4:为了交互对象之间的松耦合设计而努力 观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 案例:类似于邮件主...
  • wyzxk888
  • wyzxk888
  • 2013年06月30日 17:18
  • 728

观察者模式(Observer Pattern)

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 模式结构 观察者模式的好处: ...
  • lhc2207221755
  • lhc2207221755
  • 2014年03月21日 09:41
  • 1962

观察者模式(Observer Pattern)

定义 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Depe...
  • u011066648
  • u011066648
  • 2017年04月12日 15:33
  • 197

观察者模式(Observer Pattern)

观察者设计模式也叫做发布-订阅(Publish-Subscribe)模式。有点像杂志订阅的意思,你向杂志社订阅杂志,然后提供了自己的姓名和邮箱地址,这样杂志社就可以把你所订阅的杂志推送到你的邮箱了,而...
  • u014161864
  • u014161864
  • 2015年01月23日 08:54
  • 2711

Observer Pattern 在C#是怎么使用的(一)

最近很少加班,晚上回家闲来无聊就拿起侯捷老师的《design pattern》 重读了起来。上侯捷老师的设计模式的课是差不多两年前的事了,也还记得考试的时候每个人都带着他的书放到书桌下面一顿狂抄。 ...
  • shizhangfan
  • shizhangfan
  • 2015年11月24日 16:48
  • 111

观察者模式(Observer Pattern)

观察者模式(Observer Pattern)观察者模式(Observer Pattern)也叫发布订阅模式(Publish/subscribe),它是一个在项目中经常 的模式,其定义如下: ...
  • baiuterfkcyj
  • baiuterfkcyj
  • 2017年05月06日 12:29
  • 63
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:观察者模式(Observer Pattern)
举报原因:
原因补充:

(最多只允许输入30个字)