观察者模式是一种行为型模式,允许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的其他对象。 它定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
假如你有两种类型的对象:顾客和商店。顾客对某个特定品牌的产品非常感兴趣(例如最新型号的iPhone手机),而该产品很快将会在商店里出售。
顾客可以每天来商店看看产品是否到货。但如果商品尚未到货时,绝大多数来到商店的顾客都会空手而归。
另一方面,每次新产品到货时,商店可以向所有顾客发送邮件(可能会被视为垃圾邮件)。这样,部分顾客就无需反复前往商店了,但也可能会惹恼对新产品没有兴趣的其他顾客。
我们似乎遇到了一个矛盾:要么让顾客浪费时间检查产品是否到货,要么让商店浪费资源去通知没有需求的顾客。
由主题订阅并维护多个观察者,当主题发生变更,则所有观察者收到通知,并各自维持自己的状态。
拥有一些值得关注的状态的对象通常被称为目标,由于它要将自身的状态改变通知给其他对象,我们也将其称为发布者(publisher)。所有希望关注发布者状态变化的其他对象被称为订阅者(subscribers)。
观察者模式建议你为发布者类添加订阅机制,让每个对象都能订阅或取消订阅发布者事件流。不要害怕! 这并不像听上去那么复杂。实际上,该机制包括:
现在,无论何时发生了重要的发布者事件,它都要遍历订阅者并调用其对象的特定通知方法。
实际应用中可能会有十几个不同的订阅者类跟踪着同一个发布者类的事件,你不会希望发布者与所有这些类相耦合的。此外如果他人会使用发布者类,那么你甚至可能会对其中的一些类一无所知。
因此,所有订阅者都必须实现同样的接口,发布者仅通过该接口与订阅者交互。接口中必须声明通知方法及其参数,这样发布者在发出通知时还能传递一些上下文数据。
如果你的应用中有多个不同类型的发布者,且希望订阅者可兼容所有发布者,那么你甚至可以进一步让所有订阅者遵循同样的接口。该接口仅需描述几个订阅方法即可。这样订阅者就能在不与具体发布者类耦合的情况下通过接口观察发布者的状态。
update
方法。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 | using System;using System.Collections.Generic;using System.Threading;namespace RefactoringGuru.DesignPatterns.Observer.Conceptual{ public interface IObserver { // Receive update from subject void Update(ISubject subject); } public interface ISubject { // Attach an observer to the subject. void Attach(IObserver observer); // Detach an observer from the subject. void Detach(IObserver observer); // Notify all observers about an event. void Notify(); } // The Subject owns some important state and notifies observers when the // state changes. public class Subject : ISubject { // For the sake of simplicity, the Subject's state, essential to all // subscribers, is stored in this variable. public int State { get; set; } = -0; // List of subscribers. In real life, the list of subscribers can be // stored more comprehensively (categorized by event type, etc.). private List<IObserver> _observers = new List<IObserver>(); // The subscription management methods. public void Attach(IObserver observer) { Console.WriteLine("Subject: Attached an observer."); this._observers.Add(observer); } public void Detach(IObserver observer) { this._observers.Remove(observer); Console.WriteLine("Subject: Detached an observer."); } // Trigger an update in each subscriber. public void Notify() { Console.WriteLine("Subject: Notifying observers..."); foreach (var observer in _observers) { observer.Update(this); } } // Usually, the subscription logic is only a fraction of what a Subject // can really do. Subjects commonly hold some important business logic, // that triggers a notification method whenever something important is // about to happen (or after it). public void SomeBusinessLogic() { Console.WriteLine("\nSubject: I'm doing something important."); this.State = new Random().Next(0, 10); Thread.Sleep(15); Console.WriteLine("Subject: My state has just changed to: " + this.State); this.Notify(); } } // Concrete Observers react to the updates issued by the Subject they had // been attached to. class ConcreteObserverA : IObserver { public void Update(ISubject subject) { if ((subject as Subject).State < 3) { Console.WriteLine("ConcreteObserverA: Reacted to the event."); } } } class ConcreteObserverB : IObserver { public void Update(ISubject subject) { if ((subject as Subject).State == 0 || (subject as Subject).State >= 2) { Console.WriteLine("ConcreteObserverB: Reacted to the event."); } } } class Program { static void Main(string[] args) { // The client code. var subject = new Subject(); var observerA = new ConcreteObserverA(); subject.Attach(observerA); var observerB = new ConcreteObserverB(); subject.Attach(observerB); subject.SomeBusinessLogic(); subject.SomeBusinessLogic(); subject.Detach(observerB); subject.SomeBusinessLogic(); } }} |
---|
执行结果:
123456789101112131415161718 | Subject: Attached an observer.Subject: Attached an observer.Subject: I'm doing something important.Subject: My state has just changed to: 2Subject: Notifying observers...ConcreteObserverA: Reacted to the event.ConcreteObserverB: Reacted to the event.Subject: I'm doing something important.Subject: My state has just changed to: 1Subject: Notifying observers...ConcreteObserverA: Reacted to the event.Subject: Detached an observer.Subject: I'm doing something important.Subject: My state has just changed to: 5Subject: Notifying observers... |
---|
参考原文:观察者设计模式