关闭

观察者模式(Observer Pattern)

201人阅读 评论(0) 收藏 举报

观察者模式(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();

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:37031次
    • 积分:675
    • 等级:
    • 排名:千里之外
    • 原创:32篇
    • 转载:8篇
    • 译文:0篇
    • 评论:4条
    文章分类
    最新评论