Padrão de design do observadorObserver Design Pattern

O padrão de design do observador permite a um assinante se registrar em um provedor e receber notificações dele.The observer design pattern enables a subscriber to register with and receive notifications from a provider. Ele é adequado para qualquer cenário que requer a notificação por push.It is suitable for any scenario that requires push-based notification. O padrão define um provedor (também conhecido como assunto ou observável) e zero, um ou mais observadores.The pattern defines a provider (also known as a subject or an observable) and zero, one, or more observers. Observadores registram-se com o provedor e, sempre que uma condição, evento ou alteração de estado predefinido ocorrer, o provedor notificará automaticamente todos os observadores chamando um dos seus métodos.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. Nessa chamada de método, o provedor também pode fornecer informações sobre o estado atual para observadores.In this method call, the provider can also provide current state information to observers. No .NET Framework, o padrão de design de observador é aplicado ao implementar as interfaces genéricas System.IObservable<T> e 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. O parâmetro de tipo genérico representa o tipo que fornece informações de notificação.The generic type parameter represents the type that provides notification information.

Aplicando o padrãoApplying the Pattern

O padrão de design do observador é adequado para notificações por push distribuídas, pois oferece suporte para uma separação clara entre dois componentes diferentes ou camadas de aplicativo, como uma camada de fonte de dados (lógica de negócios) uma camada de interface do usuário (exibição).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. O padrão pode ser implementado sempre que um provedor usa retornos de chamada para fornecer informações atuais a seus clientes.The pattern can be implemented whenever a provider uses callbacks to supply its clients with current information.

A implementação do padrão exige que você forneça o seguinte:Implementing the pattern requires that you provide the following:

  • Um provedor ou o assunto, que é o objeto que envia notificações para observadores.A provider or subject, which is the object that sends notifications to observers. Um provedor é uma classe ou estrutura que implementa a interface IObservable<T>.A provider is a class or structure that implements the IObservable<T> interface. O provedor deve implementar um único método, IObservable<T>.Subscribe, que é chamado pelos observadores que desejam receber notificações do provedor.The provider must implement a single method, IObservable<T>.Subscribe, which is called by observers that wish to receive notifications from the provider.

  • Um observador, que é um objeto que recebe notificações de um provedor.An observer, which is an object that receives notifications from a provider. Um observador é uma classe ou estrutura que implementa a interface IObserver<T>.An observer is a class or structure that implements the IObserver<T> interface. O observador deve implementar três métodos, que são chamados pelo provedor:The observer must implement three methods, all of which are called by the provider:

  • Um mecanismo que permite que o provedor mantenha controle dos observadores.A mechanism that allows the provider to keep track of observers. Normalmente, o provedor usa um objeto de contêiner, como um objeto System.Collections.Generic.List<T>, para manter as referências às implementações de IObserver<T> que assinaram notificações.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. Usar um contêiner de armazenamento para essa finalidade permite que o provedor lidar com um número ilimitado de observadores.Using a storage container for this purpose enables the provider to handle zero to an unlimited number of observers. A ordem na qual os observadores recebem notificações não está definida. O provedor está livre para usar qualquer método para determinar a ordem.The order in which observers receive notifications is not defined; the provider is free to use any method to determine the order.

  • Uma implementação de IDisposable que permite que o provedor remova os observadores quando a notificação for concluída.An IDisposable implementation that enables the provider to remove observers when notification is complete. Observadores recebem uma referência para a implementação de IDisposable do método Subscribe, portanto, eles também podem chamar o método IDisposable.Dispose para cancelar a assinatura antes que o provedor tenha terminado de enviar notificações.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.

  • Um objeto que contém os dados que o provedor envia para seus observadores.An object that contains the data that the provider sends to its observers. O tipo desse objeto corresponde ao parâmetro de tipo genérico das interfaces IObservable<T> e IObserver<T>.The type of this object corresponds to the generic type parameter of the IObservable<T> and IObserver<T> interfaces. Embora esse objeto possa ser o mesmo que a implementação de IObservable<T>, geralmente ele é um tipo separado.Although this object can be the same as the IObservable<T> implementation, most commonly it is a separate type.

Observação

Além de implementar o padrão de design do observador, pode ser interessante explorar bibliotecas que são criadas usando as interfaces IObservable<T> e 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. Por exemplo, Extensões Reativas para .NET (Rx) consistem em um conjunto de métodos de extensão e operadores de sequência padrão LINQ para oferecer suporte à programação assíncrona.For example, Reactive Extensions for .NET (Rx) consist of a set of extension methods and LINQ standard sequence operators to support asynchronous programming.

Implementando o padrãoImplementing the Pattern

O exemplo a seguir usa o padrão de design do observador para implementar um sistema de informações de coleta de bagagem de aeroporto.The following example uses the observer design pattern to implement an airport baggage claim information system. Uma classe BaggageInfo fornece informações sobre voos que chegam e as esteiras onde as bagagens de cada voo estão disponíveis para retirada.A BaggageInfo class provides information about arriving flights and the carousels where baggage from each flight is available for pickup. Isso é mostrado no exemplo a seguir.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

Uma classe BaggageHandler é responsável por receber informações sobre os voos que chegam e as esteiras de coleta de bagagem.A BaggageHandler class is responsible for receiving information about arriving flights and baggage claim carousels. Internamente, ela mantém duas coleções:Internally, it maintains two collections:

  • observers - Uma coleção de clientes que receberão informações atualizadas.observers - A collection of clients that will receive updated information.

  • flights - Uma coleção de voos e suas respectivas esteiras.flights - A collection of flights and their assigned carousels.

Ambas as coleções são representadas por objetos List<T> genéricos que são instanciados no construtor de classe BaggageHandler.Both collections are represented by generic List<T> objects that are instantiated in the BaggageHandler class constructor. O código-fonte para a classe BaggageHandler é mostrado no exemplo a seguir.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

Clientes que desejem receber informações atualizadas devem chamar o método BaggageHandler.Subscribe.Clients that wish to receive updated information call the BaggageHandler.Subscribe method. Se o cliente não tiver assinado as notificações anteriormente, uma referência para a implementação IObserver<T> do cliente será adicionada à coleção 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.

O método BaggageHandler.BaggageStatus sobrecarregado pode ser chamado para indicar que bagagem de um voo está sendo descarregada ou que não está mais sendo descarregada.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. No primeiro caso, o método recebe um número de voo, o aeroporto que originou o voo e a esteira onde bagagem está sendo descarregada.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. No segundo caso, o método recebe apenas um número de voo.In the second case, the method is passed only a flight number. Para a bagagem que está sendo descarregada, o método verifica se as informações de BaggageInfo passadas para o método existem na coleção flights.For baggage that is being unloaded, the method checks whether the BaggageInfo information passed to the method exists in the flights collection. Se não existirem, o método adicionará as informações e chamará o método OnNext de cada observador.If it does not, the method adds the information and calls each observer's OnNext method. Para voos cuja bagagem não está mais sendo descarregada, o método verificará se as informações sobre esse voo estão armazenadas na coleção flights.For flights whose baggage is no longer being unloaded, the method checks whether information on that flight is stored in the flights collection. Se estiverem, o método chamará o método OnNext de cada observador e removerá o objeto BaggageInfo da coleção flights.If it is, the method calls each observer's OnNext method and removes the BaggageInfo object from the flights collection.

Quando o último voo do dia tiver aterrizado e sua bagagem tiver sido processada, o método BaggageHandler.LastBaggageClaimed será chamado.When the last flight of the day has landed and its baggage has been processed, the BaggageHandler.LastBaggageClaimed method is called. Esse método chama o método OnCompleted de cada observador para indicar que todas as notificações foram finalizadas e, em seguida, limpa a coleção observers.This method calls each observer's OnCompleted method to indicate that all notifications have completed, and then clears the observers collection.

O método Subscribe do provedor retorna uma implementação de IDisposable que permite que os observadores interrompam o recebimento de notificações antes que o método OnCompleted seja chamado.The provider's Subscribe method returns an IDisposable implementation that enables observers to stop receiving notifications before the OnCompleted method is called. O código-fonte para essa classe Unsubscriber(Of BaggageInfo) é mostrado no exemplo a seguir.The source code for this Unsubscriber(Of BaggageInfo) class is shown in the following example. Quando a classe é instanciada no método BaggageHandler.Subscribe, ela é passado como referência para a coleção observers e uma referência para o observador que é adicionado à coleção.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. Essas referências são atribuídas a variáveis locais.These references are assigned to local variables. Quando o método Dispose do objeto é chamado, ele verifica se o observador ainda existe na coleção observers e, em caso afirmativo, remove o observador.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

O exemplo a seguir fornece uma implementação de IObserver<T> denominada ArrivalsMonitor, que é uma classe base que exibe informações de coleta de bagagem.The following example provides an IObserver<T> implementation named ArrivalsMonitor, which is a base class that displays baggage claim information. As informações são exibidas em ordem alfabética, pelo nome da cidade de origem.The information is displayed alphabetically, by the name of the originating city. Os métodos de ArrivalsMonitor são marcados como overridable (no Visual Basic) ou virtual (em C#), portanto, todos podem ser substituídos por uma classe derivada.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

A classe ArrivalsMonitor inclui os métodos Subscribe e Unsubscribe.The ArrivalsMonitor class includes the Subscribe and Unsubscribe methods. O método Subscribe permite que a classe salve a implementação de IDisposable retornada pela chamada para Subscribe para uma variável particular.The Subscribe method enables the class to save the IDisposable implementation returned by the call to Subscribe to a private variable. O método Unsubscribe permite que a classe cancele a assinatura de notificações ao chamar a implementação de Dispose do provedor.The Unsubscribe method enables the class to unsubscribe from notifications by calling the provider's Dispose implementation. ArrivalsMonitor também fornece implementações dos métodos OnNext, OnError, e OnCompleted.ArrivalsMonitor also provides implementations of the OnNext, OnError, and OnCompleted methods. Somente a implementação de OnNext contém uma quantidade significativa de código.Only the OnNext implementation contains a significant amount of code. O método funciona com um objeto List<T> particular, classificado e genérico que mantém informações sobre os aeroportos de origem dos voos que chegam e sobre as esteiras nas quais as respectivas bagagens estarão disponíveis.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. Se a classe BaggageHandler relata um novo voo chegando, a implementação do método OnNext adiciona informações sobre esse voo à lista.If the BaggageHandler class reports a new flight arrival, the OnNext method implementation adds information about that flight to the list. Se a classe BaggageHandler relata que a bagagem do voo foi descarregada, o método OnNext remove essa voo da lista.If the BaggageHandler class reports that the flight's baggage has been unloaded, the OnNext method removes that flight from the list. Sempre que uma alteração é feita, a lista é classificada e exibida no console.Whenever a change is made, the list is sorted and displayed to the console.

O exemplo a seguir contém o ponto de entrada do aplicativo que instancia a classe BaggageHandler, bem como duas instâncias da classe ArrivalsMonitor e usa o método BaggageHandler.BaggageStatus para adicionar e remover informações sobre voos que chegam.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. Em cada caso, os observadores recebem atualizações e exibem corretamente as informações de coleta de bagagem.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
TítuloTitle DescriçãoDescription
Práticas recomendadas para o padrão de design do observadorObserver Design Pattern Best Practices São descritas as práticas recomendadas ao desenvolver aplicativos que implementam o padrão de design do observador.Describes best practices to adopt when developing applications that implement the observer design pattern.
Como implementar um provedorHow to: Implement a Provider É fornecida uma implementação passo a passo de um provedor para uma aplicativo de monitoramento de temperatura.Provides a step-by-step implementation of a provider for a temperature monitoring application.
Como implementar um observadorHow to: Implement an Observer É fornecida uma implementação passo a passo de um observador para uma aplicativo de monitoramento de temperatura.Provides a step-by-step implementation of an observer for a temperature monitoring application.