觀察器設計模式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. 觀察者會從 Subscribe 方法接收 IDisposable 實作的參考,如此觀察者同樣可以在提供者完成傳送通知之前呼叫 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.

這兩個集合都是由在 BaggageHandler 類別建構函式中執行個體化的泛型 List<T> 物件表示。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 方法,並且從 flights 集合中移除 BaggageInfo 物件。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

下列範例提供名為 ArrivalsMonitorIObserver<T> 實作,其為顯示行李提領資訊的基底類別。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 方法可讓類別將呼叫 Subscribe 所傳回的 IDisposable 實作儲存至私用變數。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.