次の方法で共有


方法: オブザーバーを実装する

オブザーバーの設計パターンでは、通知を登録するオブザーバーと、データを監視して 1 つ以上のオブザーバーに通知を送信するプロバイダーとの間の分割が必要です。 このトピックでは、オブザーバーを作成する方法について説明します。 関連トピック「 方法: プロバイダーを実装する」では、プロバイダーを作成する方法について説明します。

オブザーバーを作成するには

  1. オブザーバーを定義します。これは、 System.IObserver<T> インターフェイスを実装する型です。 たとえば、次のコードでは、Temperatureのジェネリック型引数を使用して構築されたSystem.IObserver<T>実装であるTemperatureReporterという名前の型を定義します。

    public class TemperatureReporter : IObserver<Temperature>
    
    Public Class TemperatureReporter : Implements IObserver(Of Temperature)
    
  2. プロバイダーがIObserver<T>.OnCompleted実装を呼び出す前にオブザーバーが通知の受信を停止できる場合は、プロバイダーの IObservable<T>.Subscribe メソッドによって返されるIDisposable実装を保持するプライベート変数を定義します。 プロバイダーの Subscribe メソッドを呼び出し、返された IDisposable オブジェクトを格納するサブスクリプション メソッドも定義する必要があります。 たとえば、次のコードでは、unsubscriberという名前のプライベート変数を定義し、プロバイダーのSubscribe メソッドを呼び出し、返されたオブジェクトをunsubscriber変数に割り当てるSubscribe メソッドを定義します。

    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. この機能が必要な場合、プロバイダーがその IObserver<T>.OnCompleted 実装を呼び出す前に、オブザーバーが通知の受信を停止できるようにするメソッドを定義します。 次の例では、 Unsubscribe メソッドを定義します。

    public virtual void Unsubscribe()
    {
       unsubscriber.Dispose();
    }
    
    Public Overridable Sub Unsubscribe()
        unsubscriber.Dispose()
    End Sub
    
  4. IObserver<T> インターフェイスで定義されている 3 つのメソッド (IObserver<T>.OnNextIObserver<T>.OnErrorIObserver<T>.OnCompleted) の実装を提供します。 プロバイダーとアプリケーションのニーズに応じて、 OnError メソッドと OnCompleted メソッドをスタブ実装にすることができます。 OnError メソッドは、渡されたException オブジェクトを例外として処理しないでください。また、OnCompleted メソッドはプロバイダーのIDisposable.Dispose実装を自由に呼び出すことができます。 次の例は、TemperatureReporter クラスのIObserver<T>実装を示しています。

    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 {value.Degrees}°C at {value.Date:g}");
       if (first)
       {
          last = value;
          first = false;
       }
       else
       {
          Console.WriteLine($"   Change: {value.Degrees - last.Degrees}° in {value.Date.ToUniversalTime() - last.Date.ToUniversalTime():g}");
       }
    }
    
    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
    

次の例には、温度監視アプリケーションのIObserver<T>実装を提供する、TemperatureReporter クラスの完全なソース コードが含まれています。

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 {value.Degrees}°C at {value.Date:g}");
      if (first)
      {
         last = value;
         first = false;
      }
      else
      {
         Console.WriteLine($"   Change: {value.Degrees - last.Degrees}° in {value.Date.ToUniversalTime() - last.Date.ToUniversalTime():g}");
      }
   }
}
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

こちらもご覧ください