深入浅出设计模式——观察者模式(Observer Pattern)

模式动机
 
建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

模式定义
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
Observer Pattern: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Frequency of use: high
UML图

模式结构
观察者模式包含如下角色:
Subject: 目标
ConcreteSubject: 具体目标
Observer: 观察者
ConcreteObserver: 具体观察者

模式分析
观察者模式描述了如何建立对象与对象之间的依赖关系,如何构造满足这种需求的系统。
这一模式中的关键对象是观察目标和观察者,一个目标可以有任意数目的与之相依赖的观察者,一旦目标的状态发生改变,所有的观察者都将得到通知。
作为对这个通知的响应,每个观察者都将即时更新自己的状态,以与目标状态同步,这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。

模式实例与解析
老板回来?我不知道!—观察者模式示例代码
体系结构

Subject: 目标 ISubject.cs

namespace ObserverPattern
{
    interface ISubject
    {
        void Attach(Observer observer);
        void Detach(Observer observer);
        void Notify();
        string SubjectState
        {
            get;
            set;
        }
    }
}

ConcreteSubject: 具体目标 Secretary.cs

using System.Collections.Generic;

namespace ObserverPattern
{
    //前台秘书类
    class Secretary : ISubject
    {
        //同事列表
        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; }
        }
    }
}

Boss.cs

using System.Collections.Generic;

namespace ObserverPattern
{
    class Boss : ISubject
    {
        //同事列表
        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; }
        }
    }
}

Observer: 观察者 Observer.cs

namespace ObserverPattern
{
    abstract class Observer
    {
        protected string name;
        protected ISubject sub;
        public Observer(string name, ISubject sub)
        {
            this.name = name;
            this.sub = sub;
        }
        public abstract void Update();
    }
}

ConcreteObserver: 具体观察者 StockObserver.cs

using System;

namespace ObserverPattern
{
    //看股票的同事
    class StockObserver : Observer
    {
        public StockObserver(string name, ISubject sub)
            : base(name, sub)
        {
        }
        public override void Update()
        {
            Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SubjectState, name);
        }
    }
}

NBAObserver.cs

using System;

namespace ObserverPattern
{
    class NBAObserver : Observer
    {
        public NBAObserver(string name, ISubject sub)
            : base(name, sub)
        {
        }
        public override void Update()
        {
            Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SubjectState, name);
        }
    }
}

Client:客户类

using System;

namespace ObserverPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Secretary secretary = new Secretary();
            StockObserver stockObserver1 = new StockObserver("张三", secretary);
            NBAObserver stockObserver2 = new NBAObserver("李四", secretary);
            //前台记下了两位同事
            secretary.Attach(stockObserver1);
            secretary.Attach(stockObserver2);
            //发现老板回来
            secretary.SubjectState = "老板回来了";
            //通知两个同事
            secretary.Notify();
            Console.Read();
        }
    }
}

模式优缺点
观察者模式的优点
 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
 观察者模式在观察目标和观察者之间建立一个抽象的耦合。
 观察者模式支持广播通信。
 观察者模式符合“开闭原则”的要求。

观察者模式的缺点
 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

模式适用环境
在以下情况下可以使用观察者模式:
 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
 一个对象必须通知其他对象,而并不知道这些对象是谁。
 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

【声明与感谢】
本文,站在许多巨人的肩膀上,借鉴和引用了许多他人拥有版权的作品或著述,在此,对前人们的贡献致谢。并同时公布引用的内容、原作者或来源(一些来源于互联网的内容本人无法追述本源,深表遗憾)。

【参考文献】
《设计模式—可复用面向对象软件的基础》作者: [美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 译者: 李英军 / 马晓星 / 蔡敏 / 刘建中 等 机械工业出版社
《重构—改善既有代码的设计》作者: Martin Fowler译者:候捷 中国电力出版社
《敏捷软件开发—原则、模式与实践》作者: Robert C. Martin 清华大学出版社
《程序员修炼之道—从小工到专家》作者: Andrew Hunt / David Thomas 电子工业出版社
《Head First 设计模式》作者: 弗里曼 译者: O'Reilly Taiwan公司 中国电力出版社
《设计模式之禅》 作者: 秦小波 机械工业出版社
MSDN WebCast 《C#面向对象设计模式纵横谈》 讲师:李建忠
刘伟. 设计模式. 北京:清华大学出版社, 2011.
刘伟. 设计模式实训教程. 北京:清华大学出版社, 2012.
《大话设计模式》 作者: 程杰 清华大学出版社
《C#图解教程》作者: 索利斯 译者: 苏林 / 朱晔 人民邮电出版社
《你必须知道的.NET》作者: 王涛
《项目中的.NET》作者: 李天平 电子工业出版社
《Microsoft .NET企业级应用架构设计》作者: (美)埃斯波西托等编著 译者: 陈黎夫
http://www.dofactory.com/Patterns/Patterns.aspx .NET Design Patterns
http://www.cnblogs.com/zhenyulu 博客作者:吕震宇
http://www.cnblogs.com/terrylee 博客作者:李会军
http://www.cnblogs.com/anlyren/ 博客作者:anlyren
http://www.cnblogs.com/idior 博客作者:idior
http://www.cnblogs.com/allenlooplee 博客作者:Allen lee
http://blog.csdn.net/ai92 博客作者:ai92
http://www.cnblogs.com/umlonline/ 博客作者:张传波
http://www.cnblogs.com/lovecherry/ 博客作者:LoveCherry

posted @ 2015-01-04 10:59  Bobby0322  阅读(6930)  评论(1编辑  收藏  举报