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();
        }
    }
}