C++と色々

主にC++やプログラムに関する記事を投稿します。

Observerパターン

Observerパターンの理解が怪しかったのでサンプル書いてみた。
こ、これであってるのか?!

#include <iostream>
#include <string>
#include <list>

class IObserver;

class ISubject
{
public:
	virtual void Push(IObserver* observer) = 0;
	virtual void Notify() = 0;
};

class IObserver
{
public:
	virtual void Update() = 0;
};

class Data : public ISubject
{
	std::list<IObserver*> list;
	int data;
public:
	void Push(IObserver* observer)
	{
		list.push_back(observer);
	}
	void Notify()
	{
		for(auto it = list.begin(); it != list.end(); it++)
		{
			(*it)->Update();
		}
	}

	int GetData() const
	{
		return data;
	}

	void SetData(int data)
	{
		this->data = data;
		Notify();
	}
};

class Graph : public IObserver
{
	int value;
	ISubject* subject;
public:
	Graph(ISubject* subject) : subject(subject)
	{
		subject->Push(this);
	}
	void Update()
	{
		value = dynamic_cast<Data*>(subject)->GetData();//dynamic_castでも?
	}
	void Show() const
	{
		std::cout << "Graph value = " << value << std::endl;
	}
};

class File : public IObserver
{
	int value;
	ISubject* subject;
public:
	File(ISubject* subject) : subject(subject)
	{
		subject->Push(this);
	}

	void Update()
	{
		value = static_cast<Data*>(subject)->GetData();//static_castでも?
	}
	void Show() const
	{
		std::cout << "File value = " << value << std::endl;
	}
};

int main()
{
	Data d;
	Graph g(&d);
	File f(&d);
	std::string str;

	do
	{
		std::cout << "input mode" << std::endl;
		std::cout << "q:quit d:set data s:show data" << std::endl;
		std::cin >> str;
		if(str == "d")
		{
			int i;
			std::cout << "input data" << std::endl;
			std::cin >> i;
			d.SetData(i);
		}
		if(str == "s")
		{
			g.Show();
			f.Show();
		}
	}while(str != "q");

	return 0;
}

実行結果例

input mode
q:quit d:set data s:show data
d
input data
5
input mode
q:quit d:set data s:show data
s
Graph value = 5
File value = 5
input mode
q:quit d:set data s:show data
q
続行するには何かキーを押してください . . .

関係ないところに疑問が。
基底クラスのポインタ型を派生クラスのポインタ型にキャストする時って、static_castでもdynamic_castでもいいんでしたっけ…?;

オブサーバーパターンはこれでいいのかな…でもこれだとObserverインターフェイスを実装しているクラスはISubjectのポインタ保持していて、
なんかおかしい気がする…IObserver::Update(ISubject* subject)にすれば保持する必要も無さそうだが…
どうやってObserverリストに追加するかが問題になるな…どのISubjectの派生クラスにキャストして、どのメソッド呼べばいいかもわからんし…うーん。

参考文献
株式会社テクノロジックアート:"独習デザインパターンC++"、翔泳社(2008)