728x90
이번 시간에는 Design pattern의 종류 중 하나인 observer pattern을 공부해본다.
정의 : 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다. 발행/구독 모델로 알려져 있기도 하다.
위키피디아 설명
observer pattern의 목적은 상태를 표시하는 display와 개체 자체를 분리하는 것이다.
또한, observer pattern은 같은 데이터를 다양한 display로 나타낼 수 있고, object(객체)가 변경되면, 모든 display를 자동으로 업데이트시켜줄 수 있다. display는 나중에 추가될 수 도 있다.
display는 막대형, 꺽은선형, 원형, 분산형, 지도형, 히스토그램 등 다양하게 display 할 수 있다.
장점
- 실시간으로 한 객체의 변경사항을 다른 객체에 전파할 수 있다.
- 상태를 표시하는 display와 객체 자체를 분리할 수 있다.
- 객체간의 의존성을 제거할 수 있다.
- 알아서 타입에 맞게 display를 나타낼 수 있다.
단점
- 속도의 최적화가 어렵다. 상태 관리가 힘들다.
- 모든 observer를 업데이트하기 때문에 필요 없는 observer도 업데이트하게 된다.
A UML model of the Observer pattern
UML 다이어그램으로는 다음과 같이 표현된다. 화살표는 상속관계를 나타내 준다.
- Subject: 모든 observer를 추적하고 observer를 추가(Attach)하거나 제거(Detach)할 수 있다. 또한 데이터가 변경되면 observer를 업데이트(Notify)할 수 있다.
- ConcreteSubject: 이 클래스는 subject를 구현하는 실제 클래스이다. 실제 데이터를 가져오고(GetState) 넘겨주며 Subject에 업데이트(Notify)를 알려준다.
- Observer: 변경이 있을 때마다 호출되어야하는 메소드를 정의하는 인터페이스를 나타낸다.
- ConcreteObserver: 변경 사항에 따라 자체적으로 업데이트해야 하는 클래스이다. observer를 구현하고 concretesubject에 등록하면 업데이트를 수신하도록 한다.
C++ 구현
코드구현은 다음과 같이 할 수 있다.
-
Subject
//Header File
#pragma once
#include <vector>
#include <list>
#include "shop.h"
class ASubject
{
//Lets keep a track of all the shops we have observing
std::vector<Shop*> list;
public:
void Attach(Shop *product);
void Detach(Shop *product);
void Notify(float price);
};
//CPP File
#include "ASubject.h"
#include <algorithm>
using namespace std;
void ASubject::Attach(Shop *shop)
{
list.push_back(shop);
}
void ASubject::Detach(Shop *shop)
{
list.erase(std::remove(list.begin(), list.end(), shop), list.end());
}
void ASubject::Notify(float price)
{
for(vector<Shop*>::const_iterator iter = list.begin(); iter != list.end(); ++iter)
{
if(*iter != 0)
{
(*iter)->Update(price);
}
}
}
-
concreteSubject
//Header File
#pragma once
#include "ASubject.h"
class DummyProduct : public ASubject
{
public:
void ChangePrice(float price);
};
//CPP File
#include "DummyProduct.h"
void DummyProduct::ChangePrice(float price)
{
Notify(price);
}
-
Observer
#pragma once
class IObserver
{
public:
virtual void Update(float price) = 0;
};
-
Concrete Observer
//Header File
#pragma once
#include <iostream>
#include <string>
#include "IObserver.h"
class Shop : IObserver
{
//Name of the Shop
std::string name;
float price;
public:
Shop(std::string n);
void Update(float price);
};
//CPP File
#include "Shop.h"
Shop::Shop(std::string name)
{
this->name = name;
}
void Shop::Update(float price)
{
this->price = price;
//Lets print on console just to test the working
std::cout << "Price at "<< name << " is now "<< price << "\n";
}
-
testcode
int main(int argc, char* argv[])
{
DummyProduct product;
// We have four shops wanting to keep updated price set by product owner
Shop shop1("Shop 1");
Shop shop2("Shop 2");
product.Attach(&shop1);
product.Attach(&shop2);
//Now lets try changing the products price, this should update the shops automatically
product.ChangePrice(23.0f);
//Now shop2 is not interested in new prices so they unsubscribe
product.Detach(&shop2);
//Now lets try changing the products price again
product.ChangePrice(26.0f);
getchar();
return 0;
}
위키피디아 - ko.wikipedia.org/wiki/%EC%98%B5%EC%84%9C%EB%B2%84_%ED%8C%A8%ED%84%B4
코드 - www.codeproject.com/Articles/328365/Understanding-and-Implementing-Observer-Pattern-2
728x90
댓글