观察者设计模式Observer Design Pattern

观察者设计模式使订阅者能够从提供程序注册并接收通知。The observer design pattern enables a subscriber to register with and receive notifications from a provider. 它适用于需要基于推送的通知的任何方案。It is suitable for any scenario that requires push-based notification. 此模式定义提供程序(亦称为“使用者”或“可观察对象”),以及零个、一个或多个观察者。 The pattern defines a provider (also known as a subject or an observable) and zero, one, or more observers. 观察者注册提供程序,并且每当预定义的条件、事件或状态发生更改时,该提供程序会通过调用其方法之一来自动通知所有观察者。Observers register with the provider, and whenever a predefined condition, event, or state change occurs, the provider automatically notifies all observers by calling one of their methods. 在此方法调用中,该提供程序还可向观察者提供当前状态信息。In this method call, the provider can also provide current state information to observers. 在 .NET Framework 中,通过实现泛型 System.IObservable<T>System.IObserver<T> 接口来应用观察者设计模式。 泛型类型参数表示提供通知信息的类型。In the .NET Framework, the observer design pattern is applied by implementing the generic System.IObservable<T> and System.IObserver<T> interfaces. 泛型类型参数表示提供通知信息的类型。The generic type parameter represents the type that provides notification information.

应用模式Applying the Pattern

观察者设计模式适用于分布式基于推送的通知,因为它支持两个不同的组件或应用程序层(如数据源(业务逻辑)层和用户界面(显示)层)之间完全分离。The observer design pattern is suitable for distributed push-based notifications, because it supports a clean separation between two different components or application layers, such as a data source (business logic) layer and a user interface (display) layer. 每当提供程序使用回调向其客户端提供当前信息时,均可以实现此模式。The pattern can be implemented whenever a provider uses callbacks to supply its clients with current information.

实现此模式要求提供以下内容:Implementing the pattern requires that you provide the following:

  • 提供程序或主题,即将通知发送给观察者的对象。A provider or subject, which is the object that sends notifications to observers. 提供程序是实现 IObservable<T> 接口的类或结构。A provider is a class or structure that implements the IObservable<T> interface. 提供程序必须实现单个方法 IObservable<T>.Subscribe,该方法由希望从提供程序接收通知的观察者调用。The provider must implement a single method, IObservable<T>.Subscribe, which is called by observers that wish to receive notifications from the provider.

  • 观察者,即从提供程序接收通知的对象。An observer, which is an object that receives notifications from a provider. 观察者是实现 IObserver<T> 接口的类或结构。An observer is a class or structure that implements the IObserver<T> interface. 观察者必须实现以下三个方法,这三个方法均由提供程序调用:The observer must implement three methods, all of which are called by the provider:

  • 允许提供程序跟踪观察者的一种机制。A mechanism that allows the provider to keep track of observers. 通常情况下,提供程序使用容器对象(如 System.Collections.Generic.List<T> 对象)来保存对已订阅通知的 IObserver<T> 实现的引用。Typically, the provider uses a container object, such as a System.Collections.Generic.List<T> object, to hold references to the IObserver<T> implementations that have subscribed to notifications. 将存储容器用于此目的使提供程序能够处理零到无限数量的观察者。Using a storage container for this purpose enables the provider to handle zero to an unlimited number of observers. 未定义观察者接收通知的顺序;提供程序可以随意使用任何方法来确定顺序。The order in which observers receive notifications is not defined; the provider is free to use any method to determine the order.

  • IDisposable 实现,它使提供程序在能够通知完成时删除观察者。An IDisposable implementation that enables the provider to remove observers when notification is complete. 观察者从 IDisposable 方法接收对 Subscribe 实现的引用,因此它们还可以调用 IDisposable.Dispose 方法,以便在提供程序已完成发送通知之前取消订阅。Observers receive a reference to the IDisposable implementation from the Subscribe method, so they can also call the IDisposable.Dispose method to unsubscribe before the provider has finished sending notifications.

  • 包含提供程序发送到其观察者的数据的对象。An object that contains the data that the provider sends to its observers. 此对象的类型对应 IObservable<T>IObserver<T> 接口的泛型类型参数。The type of this object corresponds to the generic type parameter of the IObservable<T> and IObserver<T> interfaces. 尽管此对象可与 IObservable<T> 实现相同,但通常情况下,它是一个单独的类型。Although this object can be the same as the IObservable<T> implementation, most commonly it is a separate type.

备注

除实现观察者设计模式外,你还可能对浏览使用 IObservable<T>IObserver<T> 接口构建的库感兴趣。In addition to implementing the observer design pattern, you may be interested in exploring libraries that are built using the IObservable<T> and IObserver<T> interfaces. 例如,Reactive Extensions for .NET (Rx) 包含一组支持异步编程的扩展方法和 LINQ 标准序列运算符。For example, Reactive Extensions for .NET (Rx) consist of a set of extension methods and LINQ standard sequence operators to support asynchronous programming.

实现模式Implementing the Pattern

下面的示例使用观察者设计模式来实现机场行李认领信息系统。The following example uses the observer design pattern to implement an airport baggage claim information system. BaggageInfo 类提供有关到达航班以及可领取每次航班行李的行李传送带的信息。A BaggageInfo class provides information about arriving flights and the carousels where baggage from each flight is available for pickup. 如以下示例所示。It is shown in the following example.

using System;
using System.Collections.Generic;

public class BaggageInfo
{
   private int flightNo;
   private string origin;
   private int location;

   internal BaggageInfo(int flight, string from, int carousel)
   {
      this.flightNo = flight;
      this.origin = from;
      this.location = carousel;
   }

   public int FlightNumber {
      get { return this.flightNo; }
   }

   public string From {
      get { return this.origin; }
   }

   public int Carousel {
      get { return this.location; }
   }
}
Public Class BaggageInfo
   Private flightNo As Integer
   Private origin As String
   Private location As Integer

   Friend Sub New(ByVal flight As Integer, ByVal from As String, ByVal carousel As Integer)
      Me.flightNo = flight
      Me.origin = from
      Me.location = carousel
   End Sub

   Public ReadOnly Property FlightNumber As Integer
      Get
         Return Me.flightNo
      End Get
   End Property

   Public ReadOnly Property From As String
      Get
         Return Me.origin
      End Get
   End Property

   Public ReadOnly Property Carousel As Integer
      Get
         Return Me.location
      End Get
   End Property
End Class

BaggageHandler 类负责接收有关到达航班和行李认领传送带的信息。A BaggageHandler class is responsible for receiving information about arriving flights and baggage claim carousels. 在内部,它维护两个集合:Internally, it maintains two collections:

  • observers - 将接收更新的信息的客户端集合。observers - A collection of clients that will receive updated information.

  • flights - 航班及其指定行李传送带的集合。flights - A collection of flights and their assigned carousels.

这两个集合都由在 List<T> 类构造函数中实例化的泛型 BaggageHandler 对象表示。Both collections are represented by generic List<T> objects that are instantiated in the BaggageHandler class constructor. 下面的示例演示了 BaggageHandler 类的源代码。The source code for the BaggageHandler class is shown in the following example.

public class BaggageHandler : IObservable<BaggageInfo>
{
   private List<IObserver<BaggageInfo>> observers;
   private List<BaggageInfo> flights;

   public BaggageHandler()
   {
      observers = new List<IObserver<BaggageInfo>>();
      flights = new List<BaggageInfo>();
   }

   public IDisposable Subscribe(IObserver<BaggageInfo> observer)
   {
      // Check whether observer is already registered. If not, add it
      if (! observers.Contains(observer)) {
         observers.Add(observer);
         // Provide observer with existing data.
         foreach (var item in flights)
            observer.OnNext(item);
      }
      return new Unsubscriber<BaggageInfo>(observers, observer);
   }

   // Called to indicate all baggage is now unloaded.
   public void BaggageStatus(int flightNo)
   {
      BaggageStatus(flightNo, String.Empty, 0);
   }

   public void BaggageStatus(int flightNo, string from, int carousel)
   {
      var info = new BaggageInfo(flightNo, from, carousel);

      // Carousel is assigned, so add new info object to list.
      if (carousel > 0 && ! flights.Contains(info)) {
         flights.Add(info);
         foreach (var observer in observers)
            observer.OnNext(info);
      }
      else if (carousel == 0) {
         // Baggage claim for flight is done
         var flightsToRemove = new List<BaggageInfo>();
         foreach (var flight in flights) {
            if (info.FlightNumber == flight.FlightNumber) {
               flightsToRemove.Add(flight);
               foreach (var observer in observers)
                  observer.OnNext(info);
            }
         }
         foreach (var flightToRemove in flightsToRemove)
            flights.Remove(flightToRemove);

         flightsToRemove.Clear();
      }
   }

   public void LastBaggageClaimed()
   {
      foreach (var observer in observers)
         observer.OnCompleted();

      observers.Clear();
   }
}
Public Class BaggageHandler : Implements IObservable(Of BaggageInfo)

   Private observers As List(Of IObserver(Of BaggageInfo))
   Private flights As List(Of BaggageInfo)

   Public Sub New()
      observers = New List(Of IObserver(Of BaggageInfo))
      flights = New List(Of BaggageInfo)
   End Sub

   Public Function Subscribe(ByVal observer As IObserver(Of BaggageInfo)) As IDisposable _
                   Implements IObservable(Of BaggageInfo).Subscribe
      ' Check whether observer is already registered. If not, add it
      If Not observers.Contains(observer) Then
         observers.Add(observer)
         ' Provide observer with existing data.
         For Each item In flights
            observer.OnNext(item)
         Next
      End If
      Return New Unsubscriber(Of BaggageInfo)(observers, observer)
   End Function

   ' Called to indicate all baggage is now unloaded.
   Public Sub BaggageStatus(ByVal flightNo As Integer)
      BaggageStatus(flightNo, String.Empty, 0)
   End Sub

   Public Sub BaggageStatus(ByVal flightNo As Integer, ByVal from As String, ByVal carousel As Integer)
      Dim info As New BaggageInfo(flightNo, from, carousel)

      ' Carousel is assigned, so add new info object to list.
      If carousel > 0 And Not flights.Contains(info) Then
         flights.Add(info)
         For Each observer In observers
            observer.OnNext(info)
         Next
      ElseIf carousel = 0 Then
         ' Baggage claim for flight is done
         Dim flightsToRemove As New List(Of BaggageInfo)
         For Each flight In flights
            If info.FlightNumber = flight.FlightNumber Then
               flightsToRemove.Add(flight)
               For Each observer In observers
                  observer.OnNext(info)
               Next
            End If
         Next
         For Each flightToRemove In flightsToRemove
            flights.Remove(flightToRemove)
         Next
         flightsToRemove.Clear()
      End If
   End Sub

   Public Sub LastBaggageClaimed()
      For Each observer In observers
         observer.OnCompleted()
      Next
      observers.Clear()
   End Sub
End Class

想要接收更新的信息的客户端调用 BaggageHandler.Subscribe 方法。Clients that wish to receive updated information call the BaggageHandler.Subscribe method. 如果客户端以前未订阅通知,则将对客户端的 IObserver<T> 实现的引用添加到 observers 集合中。If the client has not previously subscribed to notifications, a reference to the client's IObserver<T> implementation is added to the observers collection.

可调用重载的 BaggageHandler.BaggageStatus 方法来指示是正在卸载航班行李还是不再卸载航班行李。The overloaded BaggageHandler.BaggageStatus method can be called to indicate that baggage from a flight either is being unloaded or is no longer being unloaded. 在第一种情况下,该方法传递航班号、航班起飞机场和正在卸载行李的传送带。In the first case, the method is passed a flight number, the airport from which the flight originated, and the carousel where baggage is being unloaded. 在第二种情况下,该方法仅传递航班号。In the second case, the method is passed only a flight number. 对于正在卸载的行李,该方法检查传递到方法的 BaggageInfo 信息是否存在于 flights 集合中。For baggage that is being unloaded, the method checks whether the BaggageInfo information passed to the method exists in the flights collection. 如果不存在,该方法将添加信息,并调用每个观察者的 OnNext 方法。If it does not, the method adds the information and calls each observer's OnNext method. 对于不再卸载其行李的航班,该方法检查此航班的相关信息是否存储在 flights 集合中。For flights whose baggage is no longer being unloaded, the method checks whether information on that flight is stored in the flights collection. 如果是,则该方法调用每个观察者的 OnNext 方法,并从 BaggageInfo 集合中删除 flights 对象。If it is, the method calls each observer's OnNext method and removes the BaggageInfo object from the flights collection.

当一天中的最后一个航班已着陆并且已处理了其行李时,调用 BaggageHandler.LastBaggageClaimed 方法。When the last flight of the day has landed and its baggage has been processed, the BaggageHandler.LastBaggageClaimed method is called. 此方法调用每个观察者的 OnCompleted 方法来指示所有通知均已完成,然后再清除 observers 集合。This method calls each observer's OnCompleted method to indicate that all notifications have completed, and then clears the observers collection.

提供程序的 Subscribe 方法将返回 IDisposable 实现,该实现可使观察者在调用 OnCompleted 方法之前停止接收通知。The provider's Subscribe method returns an IDisposable implementation that enables observers to stop receiving notifications before the OnCompleted method is called. 下面的示例演示了 Unsubscriber(Of BaggageInfo) 类的源代码。The source code for this Unsubscriber(Of BaggageInfo) class is shown in the following example. 此类在 BaggageHandler.Subscribe 方法中实例化时,它将传递对 observers 集合的引用以及对添加到集合中的观察者的引用。When the class is instantiated in the BaggageHandler.Subscribe method, it is passed a reference to the observers collection and a reference to the observer that is added to the collection. 这些引用被分配给局部变量。These references are assigned to local variables. 调用对象的 Dispose 方法时,它会检查观察者是否仍存在于 observers 集合中,如果存在,则删除观察者。When the object's Dispose method is called, it checks whether the observer still exists in the observers collection, and, if it does, removes the observer.

internal class Unsubscriber<BaggageInfo> : IDisposable
{
   private List<IObserver<BaggageInfo>> _observers;
   private IObserver<BaggageInfo> _observer;

   internal Unsubscriber(List<IObserver<BaggageInfo>> observers, IObserver<BaggageInfo> observer)
   {
      this._observers = observers;
      this._observer = observer;
   }

   public void Dispose() 
   {
      if (_observers.Contains(_observer))
         _observers.Remove(_observer);
   }
}
Friend Class Unsubscriber(Of BaggageInfo) : Implements IDisposable
   Private _observers As List(Of IObserver(Of BaggageInfo))
   Private _observer As IObserver(Of BaggageInfo)

   Friend Sub New(ByVal observers As List(Of IObserver(Of BaggageInfo)), ByVal observer As IObserver(Of BaggageInfo))
      Me._observers = observers
      Me._observer = observer
   End Sub

   Public Sub Dispose() Implements IDisposable.Dispose
      If _observers.Contains(_observer) Then
         _observers.Remove(_observer)
      End If
   End Sub
End Class

下面的示例提供了名为 IObserver<T>ArrivalsMonitor 实现,它是一个显示行李认领信息的基类。The following example provides an IObserver<T> implementation named ArrivalsMonitor, which is a base class that displays baggage claim information. 根据始发城市的名称,按字母顺序显示信息。The information is displayed alphabetically, by the name of the originating city. ArrivalsMonitor 的方法标记为 overridable(在 Visual Basic 中)或 virtual(在 C# 中),因此它们都可由派生类重写。The methods of ArrivalsMonitor are marked as overridable (in Visual Basic) or virtual (in C#), so they can all be overridden by a derived class.

using System;
using System.Collections.Generic;

public class ArrivalsMonitor : IObserver<BaggageInfo>
{
   private string name;
   private List<string> flightInfos = new List<string>();
   private IDisposable cancellation;
   private string fmt = "{0,-20} {1,5}  {2, 3}";

   public ArrivalsMonitor(string name)
   {
      if (String.IsNullOrEmpty(name))
         throw new ArgumentNullException("The observer must be assigned a name.");

      this.name = name;
   }

   public virtual void Subscribe(BaggageHandler provider)
   {
      cancellation = provider.Subscribe(this);
   }

   public virtual void Unsubscribe()
   {
      cancellation.Dispose();
      flightInfos.Clear();
   }

   public virtual void OnCompleted() 
   {
      flightInfos.Clear();
   }

   // No implementation needed: Method is not called by the BaggageHandler class.
   public virtual void OnError(Exception e)
   {
      // No implementation.
   }

   // Update information.
   public virtual void OnNext(BaggageInfo info) 
   {
      bool updated = false;

      // Flight has unloaded its baggage; remove from the monitor.
      if (info.Carousel == 0) {
         var flightsToRemove = new List<string>();
         string flightNo = String.Format("{0,5}", info.FlightNumber);
         
         foreach (var flightInfo in flightInfos) {
            if (flightInfo.Substring(21, 5).Equals(flightNo)) {
               flightsToRemove.Add(flightInfo);
               updated = true;
            }
         }
         foreach (var flightToRemove in flightsToRemove)
            flightInfos.Remove(flightToRemove);

         flightsToRemove.Clear();
      }
      else {
         // Add flight if it does not exist in the collection.
         string flightInfo = String.Format(fmt, info.From, info.FlightNumber, info.Carousel);
         if (! flightInfos.Contains(flightInfo)) {
            flightInfos.Add(flightInfo);
            updated = true;
         }
      }
      if (updated) {
         flightInfos.Sort();
         Console.WriteLine("Arrivals information from {0}", this.name);
         foreach (var flightInfo in flightInfos)
            Console.WriteLine(flightInfo);

         Console.WriteLine();
      }
   }
}
Public Class ArrivalsMonitor : Implements IObserver(Of BaggageInfo)
   Private name As String
   Private flightInfos As New List(Of String)
   Private cancellation As IDisposable
   Private fmt As String = "{0,-20} {1,5}  {2, 3}"

   Public Sub New(ByVal name As String)
      If String.IsNullOrEmpty(name) Then Throw New ArgumentNullException("The observer must be assigned a name.")

      Me.name = name
   End Sub

   Public Overridable Sub Subscribe(ByVal provider As BaggageHandler)
      cancellation = provider.Subscribe(Me)
   End Sub

   Public Overridable Sub Unsubscribe()
      cancellation.Dispose()
      flightInfos.Clear()
   End Sub

   Public Overridable Sub OnCompleted() Implements System.IObserver(Of BaggageInfo).OnCompleted
      flightInfos.Clear()
   End Sub

   ' No implementation needed: Method is not called by the BaggageHandler class.
   Public Overridable Sub OnError(ByVal e As System.Exception) Implements System.IObserver(Of BaggageInfo).OnError
      ' No implementation.
   End Sub

   ' Update information.
   Public Overridable Sub OnNext(ByVal info As BaggageInfo) Implements System.IObserver(Of BaggageInfo).OnNext
      Dim updated As Boolean = False

      ' Flight has unloaded its baggage; remove from the monitor.
      If info.Carousel = 0 Then
         Dim flightsToRemove As New List(Of String)
         Dim flightNo As String = String.Format("{0,5}", info.FlightNumber)
         For Each flightInfo In flightInfos
            If flightInfo.Substring(21, 5).Equals(flightNo) Then
               flightsToRemove.Add(flightInfo)
               updated = True
            End If
         Next
         For Each flightToRemove In flightsToRemove
            flightInfos.Remove(flightToRemove)
         Next
         flightsToRemove.Clear()
      Else
         ' Add flight if it does not exist in the collection.
         Dim flightInfo As String = String.Format(fmt, info.From, info.FlightNumber, info.Carousel)
         If Not flightInfos.Contains(flightInfo) Then
            flightInfos.Add(flightInfo)
            updated = True
         End If
      End If
      If updated Then
         flightInfos.Sort()
         Console.WriteLine("Arrivals information from {0}", Me.name)
         For Each flightInfo In flightInfos
            Console.WriteLine(flightInfo)
         Next
         Console.WriteLine()
      End If
   End Sub
End Class

ArrivalsMonitor 类包括 SubscribeUnsubscribe 方法。The ArrivalsMonitor class includes the Subscribe and Unsubscribe methods. Subscribe 方法使类可将由对 IDisposable 的调用返回的 Subscribe 实现保存到私有变量中。The Subscribe method enables the class to save the IDisposable implementation returned by the call to Subscribe to a private variable. Unsubscribe 方法使类可以通过调用提供程序的 Dispose 实现来取消订阅通知。The Unsubscribe method enables the class to unsubscribe from notifications by calling the provider's Dispose implementation. ArrivalsMonitor 也提供 OnNextOnErrorOnCompleted 方法的实现。ArrivalsMonitor also provides implementations of the OnNext, OnError, and OnCompleted methods. OnNext 实现包含大量的代码。Only the OnNext implementation contains a significant amount of code. 该方法处理私有的、已排序的泛型 List<T> 对象,该对象维护有关抵港航班的始发机场以及可提取行李的传送带的信息。The method works with a private, sorted, generic List<T> object that maintains information about the airports of origin for arriving flights and the carousels on which their baggage is available. 如果 BaggageHandler 类报告新的航班抵达,则 OnNext 方法实现将该航班的相关信息添加到列表中。If the BaggageHandler class reports a new flight arrival, the OnNext method implementation adds information about that flight to the list. 如果 BaggageHandler 类报告已卸载该航班的行李,则 OnNext 方法从列表中移除该航班。If the BaggageHandler class reports that the flight's baggage has been unloaded, the OnNext method removes that flight from the list. 每当进行了更改,就会对列表进行排序并向控制台显示。Whenever a change is made, the list is sorted and displayed to the console.

下面的示例包含对 BaggageHandler 类以及对 ArrivalsMonitor 类的两个实例进行实例化的应用程序入口点,并使用 BaggageHandler.BaggageStatus 方法来添加和删除有关抵港航班的信息。The following example contains the application entry point that instantiates the BaggageHandler class as well as two instances of the ArrivalsMonitor class, and uses the BaggageHandler.BaggageStatus method to add and remove information about arriving flights. 在每种情况下,观察者均接收更新,并且正确显示行李认领信息。In each case, the observers receive updates and correctly display baggage claim information.

using System;
using System.Collections.Generic;

public class Example
{
   public static void Main()
   {
      BaggageHandler provider = new BaggageHandler();
      ArrivalsMonitor observer1 = new ArrivalsMonitor("BaggageClaimMonitor1");
      ArrivalsMonitor observer2 = new ArrivalsMonitor("SecurityExit");

      provider.BaggageStatus(712, "Detroit", 3);
      observer1.Subscribe(provider);
      provider.BaggageStatus(712, "Kalamazoo", 3);
      provider.BaggageStatus(400, "New York-Kennedy", 1);
      provider.BaggageStatus(712, "Detroit", 3);
      observer2.Subscribe(provider);
      provider.BaggageStatus(511, "San Francisco", 2);
      provider.BaggageStatus(712);
      observer2.Unsubscribe();
      provider.BaggageStatus(400);
      provider.LastBaggageClaimed();
   }
}
// The example displays the following output:
//      Arrivals information from BaggageClaimMonitor1
//      Detroit                712    3
//
//      Arrivals information from BaggageClaimMonitor1
//      Detroit                712    3
//      Kalamazoo              712    3
//
//      Arrivals information from BaggageClaimMonitor1
//      Detroit                712    3
//      Kalamazoo              712    3
//      New York-Kennedy       400    1
//
//      Arrivals information from SecurityExit
//      Detroit                712    3
//
//      Arrivals information from SecurityExit
//      Detroit                712    3
//      Kalamazoo              712    3
//
//      Arrivals information from SecurityExit
//      Detroit                712    3
//      Kalamazoo              712    3
//      New York-Kennedy       400    1
//
//      Arrivals information from BaggageClaimMonitor1
//      Detroit                712    3
//      Kalamazoo              712    3
//      New York-Kennedy       400    1
//      San Francisco          511    2
//
//      Arrivals information from SecurityExit
//      Detroit                712    3
//      Kalamazoo              712    3
//      New York-Kennedy       400    1
//      San Francisco          511    2
//
//      Arrivals information from BaggageClaimMonitor1
//      New York-Kennedy       400    1
//      San Francisco          511    2
//
//      Arrivals information from SecurityExit
//      New York-Kennedy       400    1
//      San Francisco          511    2
//
//      Arrivals information from BaggageClaimMonitor1
//      San Francisco          511    2
Module Example
   Public Sub Main()
      Dim provider As New BaggageHandler()
      Dim observer1 As New ArrivalsMonitor("BaggageClaimMonitor1")
      Dim observer2 As New ArrivalsMonitor("SecurityExit")

      provider.BaggageStatus(712, "Detroit", 3)
      observer1.Subscribe(provider)
      provider.BaggageStatus(712, "Kalamazoo", 3)
      provider.BaggageStatus(400, "New York-Kennedy", 1)
      provider.BaggageStatus(712, "Detroit", 3)
      observer2.Subscribe(provider)
      provider.BaggageStatus(511, "San Francisco", 2)
      provider.BaggageStatus(712)
      observer2.Unsubscribe()
      provider.BaggageStatus(400)
      provider.LastBaggageClaimed()
   End Sub
End Module
' The example displays the following output:
'      Arrivals information from BaggageClaimMonitor1
'      Detroit                712    3
'
'      Arrivals information from BaggageClaimMonitor1
'      Detroit                712    3
'      Kalamazoo              712    3
'
'      Arrivals information from BaggageClaimMonitor1
'      Detroit                712    3
'      Kalamazoo              712    3
'      New York-Kennedy       400    1
'
'      Arrivals information from SecurityExit
'      Detroit                712    3
'
'      Arrivals information from SecurityExit
'      Detroit                712    3
'      Kalamazoo              712    3
'
'      Arrivals information from SecurityExit
'      Detroit                712    3
'      Kalamazoo              712    3
'      New York-Kennedy       400    1
'
'      Arrivals information from BaggageClaimMonitor1
'      Detroit                712    3
'      Kalamazoo              712    3
'      New York-Kennedy       400    1
'      San Francisco          511    2
'
'      Arrivals information from SecurityExit
'      Detroit                712    3
'      Kalamazoo              712    3
'      New York-Kennedy       400    1
'      San Francisco          511    2
'
'      Arrivals information from BaggageClaimMonitor1
'      New York-Kennedy       400    1
'      San Francisco          511    2
'
'      Arrivals information from SecurityExit
'      New York-Kennedy       400    1
'      San Francisco          511    2
'
'      Arrivals information from BaggageClaimMonitor1
'      San Francisco          511    2
标题Title 说明Description
监视程序设计模式最佳做法Observer Design Pattern Best Practices 描述开发实现观察者设计模式的应用程序时要采用的最佳做法。Describes best practices to adopt when developing applications that implement the observer design pattern.
如何:实现提供程序How to: Implement a Provider 为温度监控应用程序提供一个提供程序的分步实现。Provides a step-by-step implementation of a provider for a temperature monitoring application.
如何:实现监视程序How to: Implement an Observer 为温度监控应用程序提供一个观察者的分步实现。Provides a step-by-step implementation of an observer for a temperature monitoring application.