0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】Observer(デザインパターン)

Posted at

Observerとは?

あるオブジェクトの状態が変化した際に、
それに関連する他のオブジェクトに自動的に通知する設計。

  • 監視者と監視対象を疎結合にできる
  • 新しい監視者を簡単に追加できるため、拡張性が高くなる

C++

Observer.cpp
#include <iostream>
#include <vector>
#include <string>

#define STRINGIFY(x) #x

/// <summary>
/// 監視者の抽象クラス
/// </summary>
class Observer
{
public:
	/// <summary>
	/// コンストラクタ
	/// </summary>
	/// <param name="_subject">監視対象</param>
	Observer(class Subject* _subject)
	{
		subject = _subject;
	}
	/// <summary>
	/// デストラクタ
	/// </summary>
	virtual ~Observer() = default;

	virtual void Update() = 0;

	class Subject* subject; // 監視対象
};

/// <summary>
/// 監視対象の抽象クラス
/// </summary>
class Subject
{
public:
	/// <summary>
	/// コンストラクタ
	/// </summary>
	Subject()
		: observers(new std::vector<class Observer*>())
	{
		SetState(STRINGIFY(STATE::FINE));
	}
	/// <summary>
	/// デストラクタ
	/// </summary>
	virtual ~Subject()
	{
		// コンテナの中の監視者を削除
		observers->clear();

		// コンテナ自身も削除
		delete observers;
	}

	enum class STATE
	{
		FINE,	// 元気
		SOSO,	// 普通
		BAD,	// 悪い
	};

	/// <summary>
	/// 状態を取得する
	/// </summary>
	inline std::string GetState() { return state; }
	/// <summary>
	/// 状態の設定
	/// </summary>
	/// <param name="_state">新しい状態</param>
	inline void SetState(std::string _state)
	{
		state = _state;
		StateNotify();
	}

	/// <summary>
	/// 監視者の追加
	/// </summary>
	/// <param name="_observer">追加する監視者のポインタ</param>
	void Attach(class Observer* _observer)
	{
		observers->push_back(_observer);
	}
	/// <summary>
	/// 監視者の削除
	/// </summary>
	/// <param name="_observer">削除する監視者のポインタ</param>
	void Detach(class Observer* _observer)
	{
		observers->erase
		(
			remove
			(
				observers->begin(),
				observers->end(),
				_observer
			)
		);
	}

private:
	/// <summary>
	/// 状態の変化を通知する
	/// </summary>
	void StateNotify()
	{
		for (class Observer* observer : *observers)
		{
			observer->Update();
		}
	}

	std::vector<class Observer*>* observers; // 監視者
	std::string state;
};

/// <summary>
/// 状態の監視者
/// </summary>
class StateObserver
	: public Observer
{
public:
	/// <summary>
	/// コンストラクタ
	/// </summary>
	/// <param name="_subject">監視対象</param>
	StateObserver(class Subject* _subject)
	// 基底のコンストラクタはデフォルトしか呼ばれない
	// 自分でどのコンストラクタを呼ぶかを明言する
		: Observer(_subject)
	{
		// 監視者に自身を登録
		_subject->Attach(this);
	}
	/// <summary>
	/// デストラクタ
	/// </summary>
	virtual ~StateObserver()
	{
		subject->Detach(this);
	}

	/// <summary>
	/// 更新処理
	/// </summary>
	void Update() override
	{
		std::cout << "状態の監視者:" << subject->GetState() << std::endl;
	}
};

/// <summary>
/// 監視対象「プレイヤー」
/// </summary>
class Player
	: public Subject
{
public:
	/// <summary>
	/// コンストラクタ
	/// </summary>
	Player() = default;
	/// <summary>
	/// デストラクタ
	/// </summary>
	virtual ~Player() = default;
};

int main(void)
{
	//監視される対象を作成
	Player* player = new Player();

	//監視者の作成
	std::vector<Observer*> observers = { new StateObserver(player)/* , ・・・ Observerを継承したクラスを無制限で追加できる*/};

	std::cout << "状態が少し悪化" << std::endl;
	player->SetState(STRINGIFY(Player::STATE::SOSO));
	std::cout << "状態が悪化" << std::endl;
	player->SetState(STRINGIFY(Player::STATE::BAD));

	delete player;

	return 0;
}

C#

Observer.cs
using System;
using System.Collections.Generic;

/// <summary>
/// 監視者の抽象クラス
/// </summary>
public abstract class Observer
{
    public Subject subject; // 監視対象

	/// <summary>
	/// コンストラクタ
	/// </summary>
	/// <param name="_subject">監視対象</param>
	public Observer(Subject _subject)
	{
		subject = _subject;
	}

	public abstract void Update();
}

/// <summary>
/// 監視対象の抽象クラス
/// </summary>
public abstract class Subject
{
	private List<Observer> observers = new List<Observer>(); // 監視者
	public enum STATE
	{
		FINE,   // 元気
		SOSO,   // 普通
		BAD,    // 悪い
	};
	private STATE state;

	/// <summary>
	/// 状態を取得する
	/// </summary>
	public STATE GetState { get { return state; } }
	/// <summary>
	/// 状態の設定
	/// </summary>
	/// <param name="_state">新しい状態</param>
	public STATE SetState
	{
		set
		{
			state = value;
			StateNotify();
		}
	}

	/// <summary>
	/// 状態の変化を通知する
	/// </summary>
	private void StateNotify()
	{
		foreach (Observer observer in observers)
		{
			observer.Update();
		}
	}

	/// <summary>
	/// 監視者の追加
	/// </summary>
	/// <param name="_observer">追加する監視者のポインタ</param>
	public void Attach(Observer _observer)
	{
		observers.Add(_observer);
	}
	/// <summary>
	/// 監視者の削除
	/// </summary>
	/// <param name="_observer">削除する監視者のポインタ</param>
	public void Detach(Observer _observer)
	{
		observers.Remove(_observer);
	}
}

/// <summary>
/// 状態の監視者
/// </summary>
class StateObserver : Observer
{
	/// <summary>
	/// コンストラクタ
	/// </summary>
	/// <param name="_subject">監視対象</param>
	public StateObserver(Subject _subject)
		// 基底のコンストラクタはデフォルトしか呼ばれない
		// 自分でどのコンストラクタを呼ぶかを明言する
		: base(_subject)

	{
		// 監視者に自身を登録
		_subject.Attach(this);
	}

	/// <summary>
	/// 更新処理
	/// </summary>
	public override void Update()
	{
		Console.WriteLine("状態の監視者:" + subject.GetState);
	}
}

/// <summary>
/// 監視対象「プレイヤー」
/// </summary>
public class Player : Subject
{
    /// <summary>
    /// コンストラクタ
    /// </summary>
    public Player() { SetState = STATE.FINE; }
};

class Program
{
	static void Main()
	{
		//監視される対象を作成
		Player player = new Player();

		//監視者の作成
		List<Observer> observers = new List<Observer> { new StateObserver(player)/* , ・・・ Observerを継承したクラスを無制限で追加できる*/ };

		Console.WriteLine("状態が少し悪化");
		player.SetState = Player.STATE.SOSO;
		Console.WriteLine("状態が悪化");
		player.SetState = Player.STATE.BAD;
	}
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?