옵저버 패턴
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 94번째.
옵서버 패턴은 objects 간의 일대다 의존성을 정의합니다. 한 object(subject)의 상태가 변경되면 모든 종속 객체(옵서버)에 자동으로 notified됩니다. 이는 이벤트 시스템, UI 업데이트 또는 여러 객체가 변경 사항에 반응해야 하는 모든 상황에 이상적입니다.
이 패턴에는 두 가지 핵심 역할이 있습니다. 관찰자 목록을 유지하고 이들에게 알림을 보내는 Subject와 업데이트 인터페이스를 구현하는 Observers입니다.
#include <iostream>
#include <vector>
#include <algorithm>
class Observer {
public:
virtual void update(int value) = 0;
virtual ~Observer() = default;
};
class Subject {
std::vector<Observer*> observers;
int state = 0;
public:
void attach(Observer* obs) {
observers.push_back(obs);
}
void detach(Observer* obs) {
observers.erase(
std::remove(observers.begin(), observers.end(), obs),
observers.end());
}
void setState(int value) {
state = value;
notify();
}
void notify() {
for (Observer* obs : observers) {
obs->update(state);
}
}
};
class Display : public Observer {
std::string name;
public:
Display(const std::string& n) : name(n) {}
void update(int value) override {
std::cout << name << " received: " << value << "\n";
}
};
int main() {
Subject sensor;
Display screen1("Screen1"), screen2("Screen2");
sensor.attach(&screen1);
sensor.attach(&screen2);
sensor.setState(42); // 두 디스플레이 모두 알림을 받음
}setState()가 호출되면 주체는 등록된 모든 옵저버를 순회하며 해당 옵저버의 update() 메서드를 호출합니다. 옵저버는 언제든지 연결하거나 연결을 해제할 수 있으므로 시스템이 유연하고 느슨하게 결합됩니다.
한 object의 변경 사항으로 다른 objects를 업데이트해야 하지만 이러한 objects를 서로 강하게 결합하고 싶지 않을 때 Observer를 사용하세요.
챌린지
쉬움Observer 패턴을 사용하여 Weather Station 모니터링 시스템을 만들어 봅시다. 온도 데이터를 추적하고 온도가 변경될 때마다 여러 디스플레이 장치에 자동으로 알림을 보내는 기상 관측소를 만들 것입니다. 이는 이 패턴의 전형적인 실제 활용 사례입니다.
코드를 세 개의 파일로 구성합니다:
Observer.h: observer 인터페이스와 구체적인 디스플레이 observer를 define합니다.순수 가상
update(double temperature)method를 포함하는 추상Observerclass를 Create합니다. observers는 알림을 받기 위해 이 method를 Implement하며, virtual destructor도 함께 포함합니다.그런 다음
Observer에서 상속하는TemperatureDisplayclass를 Create합니다. each 디스플레이에는 constructor를 통해 설정되는 name(string)이 있습니다.update()가 호출되면 다음을 출력해야 합니다:[DisplayName]: Temperature is [temperature] degreesWeatherStation.h: temperature를 유지하고 observers에게 알림을 보내는 subject를 Create합니다.WeatherStationclass는 다음을 수행해야 합니다:- observer 포인터의 list와 current temperature를 저장합니다(
0.0으로 initialize) - observers를 등록하는
attach(Observer* obs)method를 가집니다 - observers를 제거하는
detach(Observer* obs)method를 가집니다 - temperature를 업데이트하고 attach된 모든 observers에게 알림을 보내는
setTemperature(double temp)method를 가집니다 - 각 observer에서 current temperature와 함께
update()를 호출하는 privatenotify()method를 가집니다
- observer 포인터의 list와 current temperature를 저장합니다(
main.cpp: Observer 패턴이 실제로 동작하는 모습을 보여 줍니다.세 개의 input을 읽습니다:
- 첫 번째 디스플레이의 name(string)
- 두 번째 디스플레이의 name(string)
- temperature 값(double)
제공된 names를 사용하여
WeatherStation하나와TemperatureDisplayobjects 두 개를 Create합니다. 두 디스플레이를 station에 attach한 다음 temperature를 input 값으로 설정합니다. 두 디스플레이 모두 자동으로 update를 받고 messages를 출력해야 합니다.그 후 첫 번째 디스플레이를 detach하고 input보다 5 degrees 높은 새 temperature를 설정합니다. 두 번째 디스플레이만 이 update를 받아야 합니다.
예를 들어, inputs가 Kitchen, Bedroom, 22.5인 경우:
Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degreesinputs가 Office, Lobby, 18.0인 경우:
Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degreesObserver 패턴이 어떻게 느슨하게 결합된 시스템을 만드는지 확인해 보세요. weather station은 특정 디스플레이에 대해 알 필요 없이, 단지 listening 중인 대상에게 notify하기만 합니다. observer를 detach하면 해당 observer는 자동으로 updates를 더 이상 받지 않습니다.
직접 해보기
#include <iostream>
#include <string>
#include "WeatherStation.h"
using namespace std;
int main() {
// 입력 읽기
string display1Name, display2Name;
double temperature;
cin >> display1Name;
cin >> display2Name;
cin >> temperature;
// TODO: WeatherStation 객체 생성
// TODO: 입력 이름으로 두 개의 TemperatureDisplay 객체 생성
// TODO: 두 디스플레이를 기상 관측소에 연결
// TODO: 온도를 입력 값으로 설정
// (두 디스플레이 모두 메시지를 출력해야 함)
// TODO: 첫 번째 디스플레이 분리
// TODO: 온도를 입력보다 5도 높게 설정
// (두 번째 디스플레이만 출력해야 함)
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C++ 컴파일러