Vorgehensweise: Implementieren eines Observers

Das Entwurfsmuster „Observer“ erfordert eine Trennung zwischen einem Observer, der für den Empfang von Benachrichtigungen registriert wird, und einem Anbieter, der Daten überwacht und Benachrichtigungen an mindestens einen Observer sendet. In diesem Thema wird das Erstellen eines Observers behandelt. In dem verwandten Thema Vorgehensweise: Implementieren eines Anbieters wird erläutert, wie ein Anbieter erstellt wird.

So erstellen Sie einen Observer

  1. Definieren Sie den Observer, der einen Typ zur Implementierung der System.IObserver<T>-Schnittstelle aufweist. Der folgende Code definiert z.B. einen Typ namens TemperatureReporter, der eine erstellte System.IObserver<T>-Implementierung mit einem generischen Typargument von Temperature darstellt.

    public class TemperatureReporter : IObserver<Temperature>
    
    Public Class TemperatureReporter : Implements IObserver(Of Temperature)
    
  2. Wenn der Observer den Empfang von Benachrichtigungen beenden kann, bevor der Anbieter seine IObserver<T>.OnCompleted-Implementierung aufruft, definieren Sie eine private Variable, die die von der IObservable<T>.Subscribe-Methode des Anbieters zurückgegebene IDisposable-Implementierung enthalten soll. Sie sollten auch eine Abonnementmethode definieren, die die Subscribe-Methode des Anbieters aufruft und das zurückgegebene IDisposable-Objekt speichert. Der folgende Code definiert z.B. eine private Variable mit dem Namen unsubscriber und definiert eine Subscribe-Methode, die die Subscribe-Methode des Anbieters aufruft und das zurückgegebene Objekt der unsubscriber-Variable zuweist.

    public class TemperatureReporter : IObserver<Temperature>
    {
       private IDisposable unsubscriber;
       private bool first = true;
       private Temperature last;
    
       public virtual void Subscribe(IObservable<Temperature> provider)
       {
          unsubscriber = provider.Subscribe(this);
       }
    
    Public Class TemperatureReporter : Implements IObserver(Of Temperature)
    
        Private unsubscriber As IDisposable
        Private first As Boolean = True
        Private last As Temperature
    
        Public Overridable Sub Subscribe(ByVal provider As IObservable(Of Temperature))
            unsubscriber = provider.Subscribe(Me)
        End Sub
    
  3. Wenn dieses Feature erforderlich sein sollte, definieren Sie eine Methode, die dem Observer das Beenden des Benachrichtigungsempfangs ermöglicht, bevor der Anbieter die jeweilige IObserver<T>.OnCompleted-Implementierung aufruft. Im folgenden Beispiel wird eine Unsubscribe-Methode definiert.

    public virtual void Unsubscribe()
    {
       unsubscriber.Dispose();
    }
    
    Public Overridable Sub Unsubscribe()
        unsubscriber.Dispose()
    End Sub
    
  4. Stellen Sie Implementierungen der drei durch die IObserver<T>-Schnittstelle definierten Methoden bereit: IObserver<T>.OnNext, IObserver<T>.OnError, und IObserver<T>.OnCompleted. Je nach Anbieter und den Anforderungen der Anwendung, kann es sich bei der OnError- und OnCompleted-Methode um Stubimplementierungen handeln. Hinweis: Die OnError-Methode sollte das übergebene Exception-Objekt nicht als Ausnahme behandeln, und die OnCompleted-Methode kann nach Bedarf die IDisposable.Dispose-Implementierung des Anbieters aufrufen. Im folgenden Beispiel wird die TemperatureReporter-Implementierung der IObserver<T>-Klasse veranschaulicht.

    public virtual void OnCompleted()
    {
       Console.WriteLine("Additional temperature data will not be transmitted.");
    }
    
    public virtual void OnError(Exception error)
    {
       // Do nothing.
    }
    
    public virtual void OnNext(Temperature value)
    {
       Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date);
       if (first)
       {
          last = value;
          first = false;
       }
       else
       {
          Console.WriteLine("   Change: {0}° in {1:g}", value.Degrees - last.Degrees,
                                                        value.Date.ToUniversalTime() - last.Date.ToUniversalTime());
       }
    }
    
    Public Overridable Sub OnCompleted() Implements System.IObserver(Of Temperature).OnCompleted
        Console.WriteLine("Additional temperature data will not be transmitted.")
    End Sub
    
    Public Overridable Sub OnError(ByVal [error] As System.Exception) Implements System.IObserver(Of Temperature).OnError
        ' Do nothing.
    End Sub
    
    Public Overridable Sub OnNext(ByVal value As Temperature) Implements System.IObserver(Of Temperature).OnNext
        Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date)
        If first Then
            last = value
            first = False
        Else
            Console.WriteLine("   Change: {0}° in {1:g}", value.Degrees - last.Degrees,
                                                          value.Date.ToUniversalTime - last.Date.ToUniversalTime)
        End If
    End Sub
    

Beispiel

Das folgende Beispiel enthält den vollständigen Quellcode für die TemperatureReporter-Klasse, um die IObserver<T>-Implementierung für eine Anwendung zur Temperaturüberwachung zu definieren.

public class TemperatureReporter : IObserver<Temperature>
{
   private IDisposable unsubscriber;
   private bool first = true;
   private Temperature last;

   public virtual void Subscribe(IObservable<Temperature> provider)
   {
      unsubscriber = provider.Subscribe(this);
   }

   public virtual void Unsubscribe()
   {
      unsubscriber.Dispose();
   }

   public virtual void OnCompleted()
   {
      Console.WriteLine("Additional temperature data will not be transmitted.");
   }

   public virtual void OnError(Exception error)
   {
      // Do nothing.
   }

   public virtual void OnNext(Temperature value)
   {
      Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date);
      if (first)
      {
         last = value;
         first = false;
      }
      else
      {
         Console.WriteLine("   Change: {0}° in {1:g}", value.Degrees - last.Degrees,
                                                       value.Date.ToUniversalTime() - last.Date.ToUniversalTime());
      }
   }
}
Public Class TemperatureReporter : Implements IObserver(Of Temperature)

    Private unsubscriber As IDisposable
    Private first As Boolean = True
    Private last As Temperature

    Public Overridable Sub Subscribe(ByVal provider As IObservable(Of Temperature))
        unsubscriber = provider.Subscribe(Me)
    End Sub

    Public Overridable Sub Unsubscribe()
        unsubscriber.Dispose()
    End Sub

    Public Overridable Sub OnCompleted() Implements System.IObserver(Of Temperature).OnCompleted
        Console.WriteLine("Additional temperature data will not be transmitted.")
    End Sub

    Public Overridable Sub OnError(ByVal [error] As System.Exception) Implements System.IObserver(Of Temperature).OnError
        ' Do nothing.
    End Sub

    Public Overridable Sub OnNext(ByVal value As Temperature) Implements System.IObserver(Of Temperature).OnNext
        Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date)
        If first Then
            last = value
            first = False
        Else
            Console.WriteLine("   Change: {0}° in {1:g}", value.Degrees - last.Degrees,
                                                          value.Date.ToUniversalTime - last.Date.ToUniversalTime)
        End If
    End Sub
End Class

Siehe auch