Design Pattern

Observer Pattern

sseram 2022. 8. 14. 22:37
반응형
엑셀을 사용할 때, 서로 연결된 표와 그래프를 생각해 보자.
 
 
표만 수정을 하면 그래프가 변화한다. 어떻게 구현할 수 있을까?
 
 
 
 
테이블을 만들고, 그 테이블에 여러가지 그래프들이 붙을 수 있게 한다.
그래프가 표를 관찰하고 있다가 변하면 본인도 변하게 한다.
관찰자 패턴이라 하지만... 개인적으로는 본인 밑에 달린 여러 클래스들에게 통보하는 느낌이 강하다.



 

ITable / Igraph를 생성.
graph를 table에 붙였다 땟다 할 수 있게 만들어 보자.
 

 

#include <iostream>
#include <vector>

class ITable; // class 전방선언

struct IGraph
{
	virtual void Update() = 0;
	virtual ~IGraph() {}

	ITable* AttachedTable;
};

class ITable
{
	std::vector<IGraph*> v;
public:
	std::vector<int> datalist;
	void attach(IGraph* p) {
		v.push_back(p);
		p->AttachedTable = this;
	}
	void detach(IGraph* p) {
		auto it = std::find(v.begin(), v.end(), p);
		v.erase(it);
	}
	void notify(){}
};

class Table : public ITable
{
public:
};
//----------------------
class BarGraph : public IGraph
{
public:
	void Update() override {
	}
};

class PieGraph : public IGraph
{
public:
	void Update() override {
		// pie graph 변경
	}
};

int main()
{
	Table t;
	PieGraph pg; t.attach(&pg);
	BarGraph bg; t.attach(&bg);

	t.detach(&bg);
}​
 
 
이런 식으로, table을 만들고 원한다면 그래프를 만들어 해당 테이블에 붙일 수 있게 해 두었다.
 
 
후, 테이블의 값 중 무언가가 변경되면 본인에게 붙어있는 graph들에게 알려주는 코드를 작성해 보자.
이를 위해 ITable에는 notify라는 함수를 추가하고, table에서 무언가 값을 변경 할 때마다 notify를 해 주었다.


graph가 시각적으로 변하는 것을 보기 위해, update될 때 print를 몇 개 해 보자.
 

 

#include <iostream>
#include <vector>

class ITable; // class 전방선언

struct IGraph
{
	virtual void Update() = 0;
	virtual ~IGraph() {}

	ITable* AttachedTable;
};

class ITable
{
	std::vector<IGraph*> v;
public:
	std::vector<int> datalist;
	void attach(IGraph* p) {
		v.push_back(p);
		p->AttachedTable = this;
	}
	void detach(IGraph* p) {
		auto it = std::find(v.begin(), v.end(), p);
		v.erase(it);
	}
	void notify()
	{
		for (auto p : v)
			p->Update();
	}
};

class Table : public ITable
{
public:
	Table() {}
	void AddData(int value) {
		datalist.push_back(value);
		std::cout << "Add data :" << value << "!" << std::endl;
		notify();
	}
};
//----------------------
class BarGraph : public IGraph
{
public:
	void Update() override {
		auto datalist = AttachedTable->datalist;
		for (auto data : datalist) {
			std::cout << data << std::endl;
		}
	}
};

class PieGraph : public IGraph
{
public:
	void Update() override {
		auto datalist = AttachedTable->datalist;
		for (auto data : datalist) {
			for (int i{ 0 }; i < data; i++) {
				std::cout << "*";
			}
			std::cout << std::endl;
		}
	}
};

int main()
{
	Table t;
	PieGraph pg; t.attach(&pg);
	BarGraph bg; t.attach(&bg);

	t.AddData(2);
	t.AddData(3);
	t.AddData(4);

	t.detach(&bg);

	t.AddData(2);
}

 

 

이러한 식으로 observer pattern을 구현한다.

 

현재, 모델은 QT, MFC 등의 다양한 라이브러리에서 사용되는데..
대부분의 경우, graph의 update하는 부분에서 아래와 같은 casting 하는 코드가 자주 나타난다고 한다.
 
class Table : public ITable
{
	std::vector<int> datalist;
public:
	Table() {}
	void AddData(int value) {
		datalist.push_back(value);
		std::cout << "Add data :" << value << "!" << std::endl;
		notify();
	}

	std::vector<int> getData() { return datalist; }
};
//----------------------
class BarGraph : public IGraph
{
public:
	void Update() override {

		Table* pTable = static_cast<Table*>(AttachedTable);
		auto datalist = pTable->getData();

		for (auto data : datalist) {
			std::cout << data << std::endl;
		}
	}
};

 

 

 

 

 

위의 코드를 반영하여 만든 최종 코드는 아래와 같다.

 

 

 

#include <iostream>
#include <vector>

class ITable; // class 전방선언

struct IGraph
{
	virtual void Update() = 0;
	virtual ~IGraph() {}

	ITable* AttachedTable;
};

class ITable
{
	std::vector<IGraph*> v;
public:
	void attach(IGraph* p) {
		v.push_back(p);
		p->AttachedTable = this;
	}
	void detach(IGraph* p) {
		auto it = std::find(v.begin(), v.end(), p);
		v.erase(it);
	}
	void notify()
	{
		for (auto p : v)
			p->Update();
	}
};

class Table : public ITable
{
	std::vector<int> datalist;
public:
	Table() {}
	void AddData(int value) {
		datalist.push_back(value);
		std::cout << "Add data :" << value << "!" << std::endl;
		notify();
	}

	std::vector<int> getData() { return datalist; }
};
//----------------------
class BarGraph : public IGraph
{
public:
	void Update() override {

		Table* pTable = static_cast<Table*>(AttachedTable);
		auto datalist = pTable->getData();

		for (auto data : datalist) {
			std::cout << data << std::endl;
		}
	}
};

class PieGraph : public IGraph
{
public:
	void Update() override {
		Table* pTable = static_cast<Table*>(AttachedTable);
		auto datalist = pTable->getData();

		for (auto data : datalist) {
			for (int i{ 0 }; i < data; i++) {
				std::cout << "*";
			}
			std::cout << std::endl;
		}
	}
};

int main()
{
	Table t;
	PieGraph pg; t.attach(&pg);
	BarGraph bg; t.attach(&bg);

	t.AddData(2);
	t.AddData(3);
	t.AddData(4);

	t.detach(&bg);

	t.AddData(2);
}
반응형

'Design Pattern' 카테고리의 다른 글

iterator pattern  (0) 2022.11.20
Template Method  (0) 2022.09.06
Decorator pattern  (0) 2022.07.26
factory method  (0) 2022.06.07
Composite Pattern  (0) 2022.05.18