HaPpY hApPy
Observer Pattern 옵저버 패턴 본문
옵저버 패턴,
[2013.10.26] 수정 오랜만에 다시 패턴 공부하다가 Push 방법은 있는데 Pull 방법이 없어서 추가!
Push 방법을 먼저 이해하고 Program.cs 파일 읽어보면서 보면 이해 하기 쉽다.
[신문사가 컨텐츠를 구독자에게 Push]
Push 방법은 반 강제적으로 받아야되고(이것도 물론 처리하면되지만, 리소스 낭비가 있을수있다.)
[구독자가 구매자에게 컨텐츠를 요구] (요구하기전에 업데이트된 정보가 있는지 물어볼수도있다.)
Pull 방법은 1. 업데이트된 정보가 있는지 체크, 2. 업데이트 내용을 받음 으로 처리하면 된다.
신문사와 구독자 로 이해하면 쉬움
신문사는 Subject
구독자는 Observer
신문사에 새로운 소식이 들어오면
Observer로 등록된 구독자들에게 알려줌,
HeadFirst 자바 책 예제를 보면
(Cinfo 클래스는 내가 직접 작성해서 humidity, pressure, temperture 를 빼서 클래스로 만들었다.)
class CInfo { float _temperture; float _humidity; float _pressure; public float Temperture { get { return _temperture; } set { _temperture = value; } } public float Humidity { get { return _humidity; } set { _humidity = value; } } public float Pressure { get { return _pressure; } set { _pressure = value; } } }인터페이스들
interface ISubject { void RegisterObserver(IObserver o); //구독자 등록 void RemoveObserver(IObserver o); //구독 해지 void NotifyObservers(); //새로운뭔가가 나오면 알려줌 } interface IObserver { void Update(float temp, float humidity, float pressure); //업데이트 되어야할 정보들 } interface IDisplayElement { void Display(); //정보가 있으니 표시를 해야겠죠? }그리고 WeatherData 클래스
class WeatherData : CInfo, ISubject { List이렇게 되어있고_observers; //C#에서는 List를 이용했다. public WeatherData() { _observers = new List (); } public void RegisterObserver(IObserver o) { _observers.Add(o); } public void RemoveObserver(IObserver o) { int i = _observers.IndexOf(o); if (i >= 0) { _observers.RemoveAt(i); } } public void NotifyObservers() { foreach (IObserver o in _observers) { o.Update(Temperture, Humidity, Pressure); } } public void MeasurementChanged() { NotifyObservers(); //책에서는 이런식으로 하던데 } public void setMeasurement(float temperture, float humidity, float pressure) { this.Temperture = temperture; this.Humidity = humidity; this.Pressure = pressure; MeasurementChanged(); //그냥 바로 NotifyObservers() 함수를 바로 호출해도 제대로 작동한다,..굳이 이렇게 두번에 그쳐 호출하는 이유를 모르겠다,내공 부족 } } // //<<애들은 무시 //
class Program { static void Main(string[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); //FutureConditionsDisplay futureDisplay = new FutureConditionsDisplay(weatherData); weatherData.setMeasurement(80, 65, 30.4f); } }
메인에서 위에서 처럼 하는데 내가 첨에 공부할때는 아래 방식으로 했다.
여기서 생성자 부분과 WeatherData 객체 선언 부분을 지우고
class CurrentConditionsDisplay : CInfo, IObserver, IDisplayElement { //WeatherData weatherData; 굳이 중복되게 여기 선언할 이유가 없다. //public CurrentConditionsDisplay(WeatherData weatherData) 마찬가지로 생성자에서 대입해 줄 필요도 없음. //{ // this.weatherData = weatherData; // weatherData.RegisterObserver(this); //} public void Update(float temperture, float humidity, float pressure) { this.Temperture = temperture; this.Humidity = humidity; Display(); } public void Display() { Console.WriteLine("Current coditions: " + Temperture + "F degrees and " + Humidity + "% humidity"); } }그러면 메인에서는 아래와 같이 바꾸면됨
class Program { static void Main(string[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(); weatherData.RegisterObserver(currentDisplay); //이렇게 직접 옵저버 등록 weatherData.setMeasurement(80, 65, 30.4f); } }기능은 똑같이 작동하는데,, 처음에 왜 HeadFirst 자바에서 저렇게 구현했을까(복잡해 보였다) 책에 이런 내용이 있다.
Q. Subject 에 대한 레프런스(WeatherData) 왜 저장하죠?
생성자 말고 다른 데서는 쓸 일이 없지 않나요?
A. 예 올바른 지적입니다. 하지만, 나중에 옵저버 목록에서 탈퇴해야 한다면 주제 객체에 대한 레프런스를 저장해 두면 유용하게 쓸 수 있을 것입니다.
음...유용하게라?? 언제일지 모르지만 여튼 저렇게 보관해 두는게 좋다고 한다
'DesignPattern (디자인패턴) > Head First Design Pattern' 카테고리의 다른 글
Abstract Factory Pattern (0) | 2013.07.30 |
---|---|
FactoryPattern 팩토리 패턴 (0) | 2013.07.27 |
DecoratorPattern 데코레이터 패턴 (0) | 2013.07.27 |
Strategy Pattern 스트레트지 패턴 (0) | 2013.07.26 |