22. 감시자 패턴(Observer Pattern)
22.1 개요
감시자 패턴은 하나의 개체가 여러 개체의 상태변화를 감지하는 역할을 담당하게 하는 패턴입니다. 특정 개체의 상태가 바뀌게 되었을 때 이를 반영해야 하는 개체가 여러 개 있을 수 있습니다. 이 경우에 다른 개체의 상태가 바뀌었을 때 자신도 변화를 갖어야 하기 때문에 결합도가 강하여 유연하게 프로그래밍하기 힘들어집니다. 이 경우에 감시자 패턴을 사용을 하면 결합도를 느슨하게 하여 유연한 프로그래밍을 할 수 있게 해 줍니다.
감시자 패턴에서는 감시자는 다른 개체의 상태의 변화를 통보를 받는 역할과 이 변화를 구독하기를 원하는 개체에게 알려주는 역할을 합니다. 이를 위해 감시자 개체는 상태의 변화가 발생하는 주 개체에게 상태 변화에 대한 통보를 해 줄 것을 요청하게 됩니다. 이를 구독이라 얘기합니다. 그리고 주 개체의 상태의 변화가 발생하면 구독 요청한 감시자들에게 이를 알려주게 됩니다. 이를 게시라고 얘기를 합니다.
감시자 패턴은 상태의 변화가 발생하는 개체에 따라 영향을 받는 개체가 다양할 경우에 상태의 변화를 감지하는 역할을 감시자에게 집중시키고 있습니다. 감시자가 없어도 의존 관계가 단순한 경우에는 굳이 감시자 패턴을 사용할 필요는 없을 것입니다. 하지만, 의존 관계가 복잡하거나 앞으로 복잡해 질 수 있을 경우에 감시자 패턴을 사용하여 유연성을 높일 수 있을 것입니다.
22. 2 시나리오
혁재는 지난 번에 사진 보정 응용을 만들고 나서 몇 가지 기능을 추가한다고 하네요. 사진을 보정하는 작업 공간외에도 사진의 정보와 미리 보기 기능이 필요하다면서 열심히 작업 중입니다.
"아빠, 사진이 보정되면 이에 대한 정보를 정보 뷰에도 알려주고 미리 보기 뷰에도 알려주는 것을 추가했어요."
"그래, 그럼 한 번 보여줄래?"
"아니요. 아직은 아니예요. 지금은 사진 개체가 자신의 상태가 변경이 되면 직접 정보 뷰와 보기 뷰에게 알려주게 하였는데 앞으로 다른 뷰를 확장시킬 때마다 사진 형식을 수정하는 것은 좀 아닌 것 같아 보여요."
"혁재가 이제 구현만 하는 것이 아니고 설계에도 신경쓰네."
"지난 번에 메멘토 패턴을 보고 난 후에 감시자 패턴을 잠시 본 적이 있는데 사진과 같이 상태가 변경될 경우에 이를 감시하는 감시자를 정의를 해야겠어요. 그리고 사진처럼 감시자에게 자신의 상태가 변경됨을 보고할 필요가 있는 형식에 대한 추상화도 같이 해 볼까 하는 중이예요."
"그래, 수고해라. 말하는 것 보니깐 조만간 멋있는 작품을 만날 수 있을 것 같네. 화이팅!"
//common.h
#pragma once
#pragma warning (disable:4996)
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <iomanip>
using std::ios;
#include <algorithm>
#pragma warning(disable:4482)
//Observer.h
#pragma once
class Observer
{
public:
virtual void Update()=0;
};
//Subject.h
#pragma once
#include "common.h"
#include "Observer.h"
typedef vector<Observer *> Observers;
typedef vector<Observer *>::iterator OIter;
class Subject
{
Observers observers;
public:
void AddObserver(Observer *observer)
{
observers.push_back(observer);
}
void RemoveObserver(Observer *observer)
{
OIter seek = find(observers.begin(),observers.end(),observer);
if(seek != observers.end())
{
observers.erase(seek);
}
}
void Notify()
{
OIter seek = observers.begin();
OIter end = observers.end();
Observer *observer = 0;
for( ; seek != end ; ++seek)
{
observer = *seek;
observer->Update();
}
}
};
//Picture.h
#pragma once
#include "Subject.h"
class Picture:
public Subject
{
string name;
int tone;
int brightness;
int saturation;
public:
Picture(string name,int tone,int brightness,int saturation);
void Change(int tone,int brightness,int saturation);
void View()const;
int GetTone()const;
int GetBrightness()const;
int GetSaturation()const;
string GetName()const;
};
//Picture.cpp
#include "Picture.h"
Picture::Picture(string name,int tone,int brightness,int saturation)
{
this->name = name;
this->tone = tone;
this->brightness = brightness;
this->saturation = saturation;
}
void Picture::Change(int tone,int brightness,int saturation)
{
this->tone += tone;
this->brightness += brightness;
this->saturation += saturation;
Notify();
}
void Picture::View()const
{
cout<<"사진 파일 명:"<<name<<endl;
cout<<" 색조:"<<tone<<" 명도:"<<brightness<<" 채도:"<<saturation<<endl;
}
int Picture::GetTone()const
{
return tone;
}
int Picture::GetBrightness()const
{
return brightness;
}
int Picture::GetSaturation()const
{
return saturation;
}
string Picture::GetName()const
{
return name;
}
//BrightnessViewer.h
#pragma once
#include "Observer.h"
#include "Picture.h"
class BrightnessViewer :
public Observer
{
Picture *picture;
public:
BrightnessViewer(Picture *picture)
{
this->picture = picture;
}
virtual void Update()
{
string name = picture->GetName();
int brightness = picture->GetBrightness();
cout<<"이름:"<<name<<", 명도:"<<brightness<<endl;
}
};
//SaturationViewer.h
#pragma once
#include "Observer.h"
#include "Picture.h"
class SaturationViewer :
public Observer
{
Picture *picture;
public:
SaturationViewer(Picture *picture)
{
this->picture = picture;
}
virtual void Update()
{
string name = picture->GetName();
int saturation = picture->GetSaturation();
cout<<"이름:"<<name<<", 채도:"<<saturation<<endl;
}
};
//ToneViewer.h
#pragma once
#include "Observer.h"
#include "Picture.h"
class ToneViewer :
public Observer
{
Picture *picture;
public:
ToneViewer(Picture *picture)
{
this->picture = picture;
}
virtual void Update()
{
string name = picture->GetName();
int tone = picture->GetTone();
cout<<"이름:"<<name<<", 색조:"<<tone<<endl;
}
};
//Demo.cpp
#include "ToneViewer.h"
#include "BrightnessViewer.h"
#include "SaturationViewer.h"
int main()
{
Picture *picture = new Picture("제주도의 밤",100,100,100);
Observer *observers[3];
observers[0] = new ToneViewer(picture);
observers[1] = new BrightnessViewer(picture);
observers[2] = new SaturationViewer(picture);
picture->AddObserver(observers[0]);
picture->AddObserver(observers[1]);
picture->AddObserver(observers[2]);
picture->Change(3,10,5);
delete picture;
delete observers[0];
delete observers[1];
delete observers[2];
return 0;
}
|
'프로그래밍 기술 > Escort GoF의 디자인 패턴' 카테고리의 다른 글
26. 방문자 패턴(Visitor Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
---|---|
25. 템플릿 메서드 패턴(Template Method Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
24. 전략 패턴(Strategy Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
23. 상태 패턴(State Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
21. 메멘토 패턴(Memento Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
20. 중재자 패턴(Mediator Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
19. 반복자 패턴(Iterator Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
18. 해석자 패턴(Interpreter Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
17. 명령 패턴(Command Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
16. 책임 연쇄 패턴(Chain of Responsibility Pattern)[Escort GoF의 디자인 패턴] (0) | 2016.04.04 |