オブサーバー デザイン パターン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. このパターンでは、1 つのプロバイダー (サブジェクトまたは観察可能なオブジェクトとも呼ばれます) と、0 個以上のオブザーバーを定義します。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

オブザーバー デザイン パターンは、データ ソース (ビジネス ロジック) 層とユーザー インターフェイス (表示) 層のように、2 つの異なるコンポーネントまたはアプリケーション層を明確に分離できるため、分散型のプッシュ ベースの通知に適しています。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 という 1 つのメソッドを実装する必要があります。このメソッドは、プロバイダーからの通知を受信するオブザーバーによって呼び出されます。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. オブザーバーでは、次の 3 つのメソッドを実装する必要があります。これらはすべてプロバイダーによって呼び出されます。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. たとえば、.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. その内部では、次の 2 つのコレクションが保持されます。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.

1 日の最終便が到着して手荷物の処理が完了すると、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

次の例は、ArrivalsMonitor という名前の IObserver<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 クラスには、Subscribe メソッドと Unsubscribe メソッドが含まれています。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 クラスの 2 つのインスタンスを作成し、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
TitleTitle 説明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.