Book/Head First Design Pattern
Observer Pattern
doublerabbits
2023. 8. 27. 15:52
Head First Design Pattern 개정판 옵저버 패턴 내용을 C# Console 프로젝트로 구현
ISubject.cs
using System;
namespace ObserverPattern
{
public interface ISubject
{
void RegisterObserver(IObserver o);
void RemoveObserver(IObserver o);
void NotifyObservers();
}
}
IObserver.cs
namespace ObserverPattern
{
public interface IObserver
{
void Update();
}
}
IDisplayElement.cs
namespace ObserverPattern
{
public interface IDisplayElement
{
void Display();
}
}
CurrentConditionDisplay.cs
using System;
namespace ObserverPattern
{
public class CurrentConditionDisplay : IObserver, IDisplayElement
{
private WeatherData _weatherData;
private double _temperature;
private double _humidity;
public CurrentConditionDisplay(WeatherData weatherData)
{
_weatherData = weatherData;
_weatherData.RegisterObserver(this);
}
public void Update()
{
_temperature = _weatherData.Temperature;
_humidity = _weatherData.Humidity;
Display();
}
public void Display()
{
Console.WriteLine($"현재 상태: 온도 {_temperature} F, 습도 {_humidity} %");
}
}
}
ForecastDisplay.cs
using System;
namespace ObserverPattern
{
public class ForecastDisplay : IObserver, IDisplayElement
{
private WeatherData _weatherData;
private double _currentPressure = 29.92;
private double _lastPressure;
public ForecastDisplay(WeatherData weatherData)
{
_weatherData = weatherData;
_weatherData.RegisterObserver(this);
}
public void Update()
{
_lastPressure = _currentPressure;
_currentPressure = _weatherData.Pressure;
Display();
}
public void Display()
{
Console.Write("기상 예보: ");
if (_currentPressure > _lastPressure)
{
Console.WriteLine("날씨가 좋아지고 있습니다!");
}
else if (_currentPressure == _lastPressure)
{
Console.WriteLine("지금과 비슷할 것 같습니다.");
}
else if (_currentPressure < _lastPressure)
{
Console.WriteLine("쌀쌀하며 비가 올 것 같습니다.");
}
}
}
}
HeatIndexDisplay.cs
using System;
namespace ObserverPattern
{
public class HeatIndexDisplay : IObserver, IDisplayElement
{
private WeatherData _weatherData;
private double _temperature;
private double _humidity;
private double _heatIndex;
public HeatIndexDisplay(WeatherData weatherData)
{
_weatherData = weatherData;
_weatherData.RegisterObserver(this);
}
public void Update()
{
_temperature = _weatherData.Temperature;
_humidity = _weatherData.Humidity;
_heatIndex = ComputeHeatIndex(_temperature, _humidity);
Display();
}
private double ComputeHeatIndex(double temperature, double pressure)
{
double heatIndex =
((16.923 + (0.185212 * temperature) + (5.37941 * pressure) - (0.100254 * temperature * pressure) +
(0.00941695 * (temperature * temperature)) + (0.00728898 * (pressure * pressure)) +
(0.000345372 * (temperature * temperature * pressure)) - (0.000814971 * (temperature * pressure * pressure)) +
(0.0000102102 * (temperature * temperature * pressure * pressure)) - (0.000038646 * (temperature * temperature * temperature)) + (0.0000291583 *
(pressure * pressure * pressure)) + (0.00000142721 * (temperature * temperature * temperature * pressure)) +
(0.000000197483 * (temperature * pressure * pressure * pressure)) - (0.0000000218429 * (temperature * temperature * temperature * pressure * pressure)) +
0.000000000843296 * (temperature * temperature * pressure * pressure * pressure)) -
(0.0000000000481975 * (temperature * temperature * temperature * pressure * pressure * pressure)));
return heatIndex;
}
public void Display()
{
Console.WriteLine($"체감 온도: {_heatIndex} F");
}
}
}
StatisticsDisplay.cs
using System;
namespace ObserverPattern
{
public class StatisticsDisplay : IObserver, IDisplayElement
{
private WeatherData _weatherData;
private double _lastTemp= 0;
private double _maxTemp = 0;
private double _minTemp = 200;
private double _tempSum = 0;
private int _numReadings;
public StatisticsDisplay(WeatherData weatherData)
{
_weatherData = weatherData;
_weatherData.RegisterObserver(this);
}
public void Update()
{
_lastTemp = _weatherData.Temperature;
_tempSum += _lastTemp;
_numReadings++;
if (_lastTemp > _maxTemp)
{
_maxTemp = _lastTemp;
}
if (_lastTemp < _minTemp)
{
_minTemp = _lastTemp;
}
Display();
}
public void Display()
{
Console.WriteLine($"평균/최고/최저 온도 = {_tempSum / _numReadings}/{_maxTemp}/{_minTemp}");
}
}
}
WeatherData.cs
using System.Collections.Generic;
namespace ObserverPattern
{
public class WeatherData : ISubject
{
private List<IObserver> _observers;
private double _temperature;
public double Temperature
{
get { return _temperature; }
set { _temperature = value; }
}
private double _humidity;
public double Humidity
{
get { return _humidity; }
set { _humidity = value; }
}
private double _pressure;
public double Pressure
{
get { return _pressure; }
set { _pressure = value; }
}
public WeatherData()
{
_observers = new List<IObserver>();
}
public void NotifyObservers()
{
foreach (var o in _observers)
{
o.Update();
}
}
public void RegisterObserver(IObserver o)
{
_observers.Add(o);
}
public void RemoveObserver(IObserver o)
{
_observers.Remove(o);
}
}
}
Program.cs
using System;
namespace ObserverPattern
{
internal class Program
{
static void ShowObserverPattern()
{
Console.WriteLine("[ Observer Pattern ]");
Console.WriteLine("한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식");
Console.WriteLine("일대다(one-to-many) 의존성을 정의");
}
static void Main(string[] args)
{
ShowObserverPattern();
Console.WriteLine("");
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.Temperature = 80;
weatherData.Humidity = 65;
weatherData.Pressure = 30.4;
weatherData.NotifyObservers();
weatherData.Temperature = 82;
weatherData.Humidity = 70;
weatherData.Pressure = 29.2;
weatherData.NotifyObservers();
weatherData.Temperature = 78;
weatherData.Humidity = 90;
weatherData.Pressure = 29.2;
weatherData.NotifyObservers();
Console.ReadKey();
}
}
}