オブザーバーデザインパターン
マイクロソフトのオブザーバー設計パターンを参考に気象観測システムをオブザーバーパターン(IObserver,IObservableインターフェースを活用)を使って実現テストします
クラス図
コード
namespace P57Observer
{
class WeatherStation
{
public static void Main(string[] args)
{
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
WeatherDataMonitor weatherDataMonitor = new WeatherDataMonitor();
weatherDataMonitor.Subscribe(currentConditionsDisplay);
weatherDataMonitor.Subscribe(statisticsDisplay);
weatherDataMonitor.Subscribe(forecastDisplay);
weatherDataMonitor.SetMeatuerments(new WeatherData(10, 65, 30.4f));
weatherDataMonitor.SetMeatuerments(new WeatherData(20, 65, 30.4f));
weatherDataMonitor.SetMeatuerments(new WeatherData(30, 65, 30.4f));
weatherDataMonitor.SetMeatuerments(new WeatherData(40, 65, 30.4f));
}
}
}
namespace P57Observer
{
public class WeatherData
{
public float temperature;
public float humidity;
public float pressure;
public WeatherData()
{
}
public WeatherData(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
}
}
}
using System;
namespace P57Observer
{
public class WeatherDataMonitor : IObservable<WeatherData>
{
List<IObserver<WeatherData>> observers;
public WeatherDataMonitor()
{
observers = new List<IObserver<WeatherData>>();
}
public WeatherDataMonitor(List<IObserver<WeatherData>> observers)
{
this.observers = observers;
}
public void SetMeatuerments(WeatherData weatherData)
{
Update(weatherData);
}
public IDisposable Subscribe(IObserver<WeatherData> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
public void Update(WeatherData weatherData)
{
foreach (var observer in observers)
{
observer.OnNext(weatherData);
}
}
class Unsubscriber : IDisposable
{
private List<IObserver<WeatherData>> _observers;
private IObserver<WeatherData> _observer;
public Unsubscriber(List<IObserver<WeatherData>> observers, IObserver<WeatherData> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (!(_observer == null)) _observers.Remove(_observer);
}
}
}
}
namespace P57Observer
{
internal class CurrentConditionsDisplay : IObserver<WeatherData>, IDisplayElement
{
float temperature;
float humidity;
private WeatherData weatherData;
private IDisposable? unsubscriber;
public CurrentConditionsDisplay(WeatherData weatherData)
{
this.weatherData = weatherData;
}
public void Display()
{
Console.WriteLine($"現在の気象状況:温度{temperature}度(摂氏) 湿度{humidity}%");
}
public void OnCompleted()
{
Console.WriteLine("追加の温度データは送信されません");
}
public void OnError(Exception error)
{
// Do nothing.
}
public void OnNext(WeatherData weatherData)
{
temperature = weatherData.temperature;
humidity = weatherData.humidity;
Display();
}
public virtual void Unsubscribe()
{
unsubscriber?.Dispose();
}
public virtual void Subscribe(IObservable<WeatherData> provider)
{
unsubscriber = provider.Subscribe(this);
}
}
}
namespace P57Observer
{
internal class ForecastDisplay : IObserver<WeatherData>, IDisplayElement
{
private WeatherData weatherData;
private IDisposable? unsubscriber;
public ForecastDisplay(WeatherData weatherData)
{
this.weatherData = weatherData;
}
public void Display()
{
if (weatherData.temperature > 40)
{
Console.WriteLine($"極暑になるでしょう");
}
else if (weatherData.temperature > 30)
{
Console.WriteLine($"猛暑になるでしょう");
}
else if (weatherData.temperature > 20)
{
Console.WriteLine($"暑くなるでしょう");
}
else if (weatherData.temperature > 10)
{
Console.WriteLine($"過ごしやすいでしょう");
}
else if (weatherData.temperature > 0)
{
Console.WriteLine($"肌寒いでしょう");
}
}
public void OnCompleted()
{
Console.WriteLine("追加の温度データは送信されません");
}
public void OnError(Exception error)
{
// Do nothing.
}
public void OnNext(WeatherData weatherData)
{
this.weatherData = weatherData;
Display();
}
public virtual void Unsubscribe()
{
unsubscriber?.Dispose();
}
public virtual void Subscribe(IObservable<WeatherData> provider)
{
unsubscriber = provider.Subscribe(this);
}
}
}
namespace P57Observer
{
using System.Linq;
internal class StatisticsDisplay : IObserver<WeatherData>, IDisplayElement
{
private WeatherData weatherData;
private IDisposable? unsubscriber;
List<WeatherData> weatherDatas = new List<WeatherData>();
public StatisticsDisplay(WeatherData weatherData)
{
this.weatherData = weatherData;
}
public void Display()
{
var average = weatherDatas.Average(data => data.temperature);
var min = weatherDatas.Min(data => data.temperature);
var max = weatherDatas.Max(data => data.temperature);
Console.WriteLine($"平均/最高/最低気温:{average}/{max}/{min}");
}
public void OnCompleted()
{
Console.WriteLine("追加の温度データは送信されません");
}
public void OnError(Exception error)
{
// Do nothing.
}
public void OnNext(WeatherData weatherData)
{
weatherDatas.Add(weatherData);
Display();
}
public virtual void Unsubscribe()
{
unsubscriber?.Dispose();
}
public virtual void Subscribe(IObservable<WeatherData> provider)
{
unsubscriber = provider.Subscribe(this);
}
}
}
namespace P57Observer
{
internal interface IDisplayElement
{
void Display();
}
}
結果
現在の気象状況:温度10度(摂氏) 湿度65%
平均/最高/最低気温:10/10/10
肌寒いでしょう
現在の気象状況:温度20度(摂氏) 湿度65%
平均/最高/最低気温:15/20/10
過ごしやすいでしょう
現在の気象状況:温度30度(摂氏) 湿度65%
平均/最高/最低気温:20/30/10
暑くなるでしょう
現在の気象状況:温度40度(摂氏) 湿度65%
平均/最高/最低気温:25/40/10
猛暑になるでしょう
ディスカッション
コメント一覧
まだ、コメントがありません