共用方式為


如何實作觀察者模式

觀察者設計模式要求在觀察者和提供者之間進行區分,觀察者負責註冊以接收通知,而提供者則負責監控數據,並將通知傳送給一個或多個觀察者。 本主題討論如何建立觀察者。 相關主題「如何:建立提供者」,討論了如何實作提供者。

建立觀察者

  1. 定義觀察者,這是實作 System.IObserver<T> 介面的類型。 例如,下列程式代碼定義了一個名為 TemperatureReporter 的類型,這是一個具有泛型類型參數 System.IObserver<T>的具體化 Temperature 實作。

    public class TemperatureReporter : IObserver<Temperature>
    
    Public Class TemperatureReporter : Implements IObserver(Of Temperature)
    
  2. 如果觀察者可以在提供者呼叫其 IObserver<T>.OnCompleted 實作之前停止接收通知,請定義私用變數,以保存提供者的 IDisposable 方法所傳回的 IObservable<T>.Subscribe 實作。 您還應該定義一個訂閱方法,該方法將呼叫提供者的 Subscribe 方法,並儲存返回的 IDisposable 物件。 例如,下列程式代碼會定義名為 unsubscriber 的私人變數,並定義呼叫提供者 Subscribe 方法的 Subscribe 方法,並將傳回的物件指派給 unsubscriber 變數。

    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> 介面所定義之三個方法的實作:IObserver<T>.OnNextIObserver<T>.OnErrorIObserver<T>.OnCompleted。 根據應用程式的提供者和需求,OnErrorOnCompleted 方法可以是存根實作。 請注意,OnError 方法不應該將傳遞 Exception 對象當做例外狀況來處理,而且 OnCompleted 方法可以自由呼叫提供者的 IDisposable.Dispose 實作。 下列範例顯示 IObserver<T> 類別的 TemperatureReporter 實作。

    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
    

範例

下列範例包含 TemperatureReporter 類別的完整原始程式碼,其提供溫度監視應用程式的 IObserver<T> 實作。

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

另請參閱