1.1 观察者模式定义

在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。观察者模式是满足这一要求的各种设计方案中最重要的一种。

Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式, 其是一种松耦合的设计模式。

1.2 观察者模式的结构

观察者模式的类图如下:

 事件与观察者模式

可以看出,在这个观察者模式的实现里有下面这些角色:

抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。 

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

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

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

从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以有任意多个对抽象观察者对象的引用。之所以使用抽象观察者而不是具体观察者,意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要的时候调用每一个观察者共有的Update()方法。这种做法叫做"针对抽象编程"

 

1.3 观察者代码

 

下面通过一个例子来说明Observer模式。监控某一个公司000002.SZ(深万科A)的股票价格变化,当价格发生变化的时候,通知的对象:投资者A,投资者B。炒股用户A与炒股用户B000002.SZ放入自己的自选股中【订阅股票信息】,当交易所将股票的信息发送到终端的时候,炒股用户AB能够实时观察到自己股票池中的股票000002.SZ的交易信息,并进行相应的操作。如果用户A此时觉得000002.SZ没有上涨的空间将其从自选股中剔除【取消订阅】,那么用户A此时便不再看到A的交易信息了。我们知道观察者模式定义了对象之间的一对多依赖,让多个观察者同时监听某一个主题对象,当这个主题对象发生改变时,便会通知所有的观察者更新。就拿上面的例子来说的话,股票【主题(Subject)】是依赖于用户群【观察者(Observer)】的,也就是在对象股票和用户之间是一对多的关系,同时,当对象股票交易价格变化的时候,便会通知其用户群接收行情信息。

 

代码:

public abstract class Subject
    {
        //用来存放所有的观察者对象 
        private IList<Observer> observers = new List<Observer>();

        //注册一个观察者 
        public void RegisterObserver(Observer observer)
        {
            observers.Add(observer);
        }

        //移除一个观察者 
        public void RemoveObserver(Observer observer)
        {
            observers.Remove(observer);
        }

        //通知所有的观察者 
        public void NotifyObserver()
        {
            foreach (Observer observer in observers)
            {
                //调用观察者的 DisplayMessage 来让他们自动显示交易信息
                observer.DisplayMessage();

            }
        }
  }
  
public class StockInfo:Subject
    {
        public string StockCode { get; set; }
        public double Close { get; set; }

        public StockInfo(string code, double close)
        {
            this.StockCode = code;
            this.Close = close;
        }
   }
  
public interface Observer
    {
        /// <summary> 
        /// 在接口中定义了当观察者得到主题给的通知后,自动更新自己的方法 
        /// </summary> 
        void DisplayMessage();
  }
  
public class ConcreteObserver:Observer
    {
        //保存一个具体的主题对象,来获取主题提供的信息 
        private StockInfo subject;
        private string userName;
        public ConcreteObserver(string userName,StockInfo subject) 
        {
            this.userName = userName;
            this.subject = subject;
        } 

        // 告知用户XX股票的信息
        public void DisplayMessage() 
        {
            Console.WriteLine("UserName:{0},StockCode:{1},Close:{2}", userName,subject.StockCode,subject.Close); 
        } 
      }
  
class Program
    {
        static void Main(string[] args)
        {
            //实例化一个主题对象
            StockInfo stockInfo = new StockInfo("000002.SZ", 12.16);

            //实例化观察者对象
            ConcreteObserver observerA = new ConcreteObserver("userA", stockInfo);
            ConcreteObserver observerB = new ConcreteObserver("userB", stockInfo);
            ConcreteObserver observerC = new ConcreteObserver("userC", stockInfo);

            //注册观察者
            stockInfo.RegisterObserver(observerA);
            stockInfo.RegisterObserver(observerB);

            //取消订阅
            stockInfo.RemoveObserver(observerC);

            //通知观察者最新收盘价
            stockInfo.NotifyObserver();

            Console.Read();
        }
  }
View Code

相关文章: