1. 程式人生 > 程式設計 >c# 實現觀察者模式

c# 實現觀察者模式

說明:主要參考《Head First設計模式(中文版)》,使用C#程式碼實現。

程式碼:Github

1、觀察者模式UML圖

c# 實現觀察者模式

2、氣象監測類圖

c# 實現觀察者模式

3、氣象監測程式碼(書中C#版)

3.1 Observer

public interface IObserver
{
void Update(float temperature,float humidity,float pressure);
}
public interface IDisplayElement
{
void Display();
}
public class CurrentConditionDisplay : IObserver,IDisplayElement
{
private readonly ISubject _weatherData;

private float _temperature;
private float _humidity;

public CurrentConditionDisplay(ISubject weatherData)
{
_weatherData = weatherData;
_weatherData?.RegisterObserver(this);
}

public void Update(float temperature,float pressure)
{
_temperature = temperature;
_humidity = humidity;
Display();
}

public void Display()
{
Console.WriteLine($"Current Conditions: {_temperature}F degress and {_humidity}% humidity");
}
}

3.2Subject

public interface ISubject
{
void RegisterObserver(IObserver o);
void RemoveObserver(IObserver o);
void NotifyObservers();
}
public class WeatherData : ISubject
{
//觀察者列表
private readonly List<IObserver> _observerList;

//天氣資料
private float _temperature;
private float _humidity;
private float _pressure;

public WeatherData()
{
_observerList = new List<IObserver>();
}

/// <summary>
/// 訂閱觀察者
/// </summary>
/// <param name="o">觀察者物件</param>
public void RegisterObserver(IObserver o)
{
_observerList.Add(o);
}

/// <summary>
/// 移除觀察者
/// </summary>
/// <param name="o">觀察者物件</param>
public void RemoveObserver(IObserver o)
{
if (_observerList.Contains(o))
{
_observerList.Remove(o);
}
}

/// <summary>
/// 釋出資料
/// </summary>
public void NotifyObservers()
{
foreach (var observer in _observerList)
{
observer.Update(_temperature,_humidity,_pressure);
}
}

/// <summary>
/// 資料發生改變
/// </summary>
private void MeasurementChanged()
{
NotifyObservers();
}

/// <summary>
/// 更新資料
/// </summary>
/// <param name="temperature">溫度</param>
/// <param name="humidity">溼度</param>
/// <param name="pressure">氣壓</param>
public void SetMeasurements(float temperature,float pressure)
{
_temperature = temperature;
_humidity = humidity;
_pressure = pressure;
MeasurementChanged();
}
}

3.3 測試程式碼

private static void TestWeatherData()
{
var weatherData = new WeatherData();
var currentConditionDisplay = new CurrentConditionDisplay(weatherData);

weatherData.SetMeasurements(80,65,30.4f);
weatherData.SetMeasurements(82,70,29.2f);
weatherData.SetMeasurements(78,90,29.2f);
}

4、使用C#中IObservable介面實現氣象監測

4.1 輔助類/結構體

public struct WeatherMessage
{
public float Temperature { get; set; }
public float Humidity { get; set; }
public float Pressure { get; set; }
}

public class MessageUnknownException : Exception
{
internal MessageUnknownException()
{

}
}

4.2 IObserver具體實現

class CurrentConditionDisplayX : IObserver<WeatherMessage>,IDisplayElement
{
private IDisposable _unsubscribe;

private float _temperature;
private float _humidity;

public void Subscribe(IObservable<WeatherMessage> provider)
{
if (provider != null)
{
_unsubscribe = provider.Subscribe(this);
}
}

public void Unsubscribe()
{
_unsubscribe?.Dispose();
_unsubscribe = null;
}

public void OnCompleted()
{
Console.WriteLine("CurrentConditionDisplayX: OnCompleted");
Unsubscribe();
}

public void OnError(Exception error)
{
Console.WriteLine("CurrentConditionDisplayX: OnError");
}

public void OnNext(WeatherMessage value)
{
_temperature = value.Temperature;
_humidity = value.Humidity;
Display();
}

public void Display()
{
Console.WriteLine($"Current Conditions: {_temperature}F degress and {_humidity}% humidity");
}
}

4.3IObservable具體實現

public class WeatherDataX : IObservable<WeatherMessage>
{
private readonly List<IObserver<WeatherMessage>> _observerList;

public WeatherDataX()
{
_observerList = new List<IObserver<WeatherMessage>>();
}

/// <summary>
/// 通知提供程式:某觀察程式將要接收通知。
/// </summary>
/// <param name="observer">要接收通知的物件。</param>
/// <returns>使資源釋放的觀察程式的介面。</returns>
public IDisposable Subscribe(IObserver<WeatherMessage> observer)
{
if(!_observerList.Contains(observer))
{
_observerList.Add(observer);
}
return new Unsubcriber(_observerList,observer);
}

public void SetMeasurements(Nullable<WeatherMessage> message)
{
foreach (var observer in _observerList)
{
if (!message.HasValue)
{
observer.OnError(new MessageUnknownException());
}
else
{
observer.OnNext(message.Value);
}
}
}

public void EndTransmission()
{
foreach (var observer in _observerList.ToArray())
{
if (_observerList.Contains(observer))
{
observer.OnCompleted();
}
}
_observerList.Clear();
}

private class Unsubcriber : IDisposable
{
private List<IObserver<WeatherMessage>> _observerList;
private IObserver<WeatherMessage> _observer;

public Unsubcriber(List<IObserver<WeatherMessage>> observerList,IObserver<WeatherMessage> observer)
{
_observerList = observerList;
_observer = observer;
}

public void Dispose()
{
if (_observerList != null && _observerList.Contains(_observer))
{
_observerList.Remove(_observer);
}
}
}
}

4.4 測試程式碼

private static void TestWeatherDataX()
{
var weatherData = new WeatherDataX();
var currentConditionDisplay = new CurrentConditionDisplayX();

currentConditionDisplay.Subscribe(weatherData);

weatherData.SetMeasurements(new WeatherMessage()
{
Temperature = 80,Humidity = 65,Pressure = 30.4f
});
weatherData.SetMeasurements(new WeatherMessage()
{
Temperature = 82,Humidity = 70,Pressure = 29.2f
});
weatherData.SetMeasurements(new WeatherMessage()
{
Temperature = 78,Humidity = 90,Pressure = 29.2f
});
weatherData.EndTransmission();
}

以上就是c# 實現觀察者模式的詳細內容,更多關於c# 觀察者模式的資料請關注我們其它相關文章!