소프트웨어 공부/디자인패턴

옵저버 패턴(Observer Pattern)

야곰야곰+책벌레 2022. 4. 5. 16:38
728x90
반응형

옵저버 패턴(Observer Pattern)에서는 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의한다.

일대다 관계는 주제와 옵저버에 의해 정의된다. 옵저버는 주제에 의존한다. 주제의 상태가 바뀌면 옵저버한테 연락이 간다. 연락 방법에 따라 옵저버에 있는 값이 새로운 값으로 갱신될 수도 있다. 옵저버 패턴을 구현하는 방법에는 여러 가지가 있지만, 대부분 주체(Subject) 인터페이스와 옵저버(Observer) 인터페이스가 들어있는 클래스 디자인을 바탕으로 한다.

느슨한 결합(Loose Coupling)의 위력

두 객체가 느슨하게 결합되어 있다는 것은, 그 둘이 상호작용을 하긴 하지만 서로에 대해 서로 잘 모른다는 것을 의미한다. 옵저버 패턴에서는 주체와 옵저버가 느슨하게 결합되어 있는 객체 디자인을 제공한다.

 

주게가 옵저버에 대해서 아는 것은 옵저버가 특정 인터페이스를 구현한다는 것 뿐이다.

  • 옵저버는 언제든지 새로 추가할 수 있다.
  • 주제와 옵저버는 서로 독립적으로 재사용할 수 있다.
  • 주제나 옵저버가 바뀌더라도 서로한테 영향을 미치지는 않는다.

기상 스테이션 설계

주제 구현

class CWeatherData : public CSubject
{
	list<CObserver*> observers;
	float temperature;
	float humidity;
	float pressure;

public:
	CWeatherData() = default;

	virtual void registerObserver(CObserver* o) override
	{
		observers.push_back(o);
	}
	virtual void removeObserver(CObserver* o) override
	{
		list<CObserver*>::iterator it = find(observers.begin(), observers.end(), o);

		if( it != observers.end())
			observers.erase(it);
	}
	virtual void notifyObservers() override
	{
		for (auto it = observers.begin(); it != observers.end(); ++it)
		{
			(*it)->update(temperature, humidity, pressure);
		}
	}

	void measurementsChanged()
	{
		notifyObservers();
	}
	void setmeasurements(float _temperature, float _humidity, float _pressure)
	{
		temperature = _temperature;
		humidity = _humidity;
		pressure = _pressure;
		measurementsChanged();
	}
};

인터페이스 구현

class CObserver
{
public:
	virtual void update(float temp, float humidity, float pressure) abstract;
};

class CDisplayElement
{
public:
	virtual void display() abstract;
};

class CSubject
{
public:
	virtual void registerObserver(CObserver* o) abstract;
	virtual void removeObserver(CObserver* o) abstract;
	virtual void notifyObservers() abstract;
};

옵저버 구현

class CCurrentConditionDisplay : public CObserver, public CDisplayElement
{
	float temperature;
	float humidity;
	shared_ptr<CSubject> weatherData;

public:
	CCurrentConditionDisplay(shared_ptr<CSubject> _weatherData)
	{
		weatherData = _weatherData;
		weatherData->registerObserver(this);
	}
	void update(float _temperature, float _humidity, float _pressure)
	{
		temperature = _temperature;
		humidity = _humidity;
		display();
	}
	void display()
	{
		cout << "Current condition: " << temperature << "F degree and " << humidity << "% humidity" << endl;
	}
};

WeatherStation 구현

class CWeatherStation
{
	shared_ptr<CWeatherData> weatherData;
	unique_ptr<CCurrentConditionDisplay> currentDisplay;

public:
	CWeatherStation()
	{
		weatherData = make_shared<CWeatherData>();
		currentDisplay = make_unique<CCurrentConditionDisplay>(weatherData);

		weatherData->setmeasurements(80, 65, 30.4f);
		weatherData->setmeasurements(82, 70, 29.2f);
		weatherData->setmeasurements(78, 90, 29.2f);
	}
};


int main()
{
	CWeatherStation weatherStation;
    return 0;
}

observepattern.zip
0.01MB

728x90
반응형