옵저버 패턴이란?
- 객체 간 일대다 관계를 설정하여, 한 객체의 상태 변경을 자동으로 여러 객체에 전파하는 디자인 패턴
- 이벤트 기반 시스템에 서 자주 사용
- 한 객체(Subject)의 상태가 변경되면, 등록된 여러 옵저버(Observer)들에게 자동으로 알림을 보냄
- 느슨한 결합을 유지하며, 객체 간 의존성 감소
구성 요소
1. Subject (주체/발행자)
옵저버(구독자)를 등록, 제거, 알림을 보내는 기능을 포함
상태가 변경되면, 등록된 옵저버들에게 변경 사항 알림을 보냄
2. Observer (옵저버/구독자)
update() 메서드 구현하여, Subject 상태 변경 감지하고 동작 수행
3. Concrete Subject (구체적인 주체/발행자)
Subject를 상속하며, 옵저버 목록을 관리하고 변경되면 알림을 보냄
4. Concrete Observer (구체적인 옵저버/구독자)
Observer를 상속하며, update()를 구현하여 Subject의 변경 사항 반영
실제로 순회할 데이터 컬렉션 보유
패턴 흐름
1. Concrete Subject는 Observer 목록을 관리합니다.
2. Observer 객체들은 Concrete Subject에 구독(등록) 합니다.
3. Concrete Subject의 상태가 변경되면 notifyObservers()를 호출하여 모든 옵저버에게 변경 사항을 알림을 보냅니다.
4. Concrete Observer는 update()를 실행하여 변경된 정보를 반영합니다.
옵저버 패턴 예제 (C++)
1. #include <iostream>
2. #include <vector>
3. #include <string>
4. using namespace std;
5.
6. // 1. Observer (옵저버 인터페이스)
7. class Observer {
8. public:
9. virtual void update(const string& news) = 0; // 뉴스 업데이트 메서드
10. virtual ~Observer() {}
11. };
12.
13. // 2. Subject (주체/발행자 인터페이스)
14. class Subject {
15. public:
16. virtual void addObserver(Observer* observer) = 0;
17. virtual void removeObserver(Observer* observer) = 0;
18. virtual void notifyObservers() = 0;
19. virtual ~Subject() {}
20. };
21.
22. // 3. ConcreteSubject (구체적인 주체/뉴스 채널)
23. class NewsChannel : public Subject {
24. private:
25. vector<Observer*> observers; // 옵저버 목록
26. string latestNews; // 최신 뉴스
27.
28. public:
29. void addObserver(Observer* observer) override {
30. observers.push_back(observer);
31. }
32.
33. void removeObserver(Observer* observer) override {
34. observers.erase(remove(observers.begin(), observers.end(), observer), observers.end());
35. }
36.
37. void notifyObservers() override {
38. for (Observer* observer : observers) {
39. observer->update(latestNews); // 모든 옵저버에게 뉴스 전달
40. }
41. }
42.
43. void publishNews(const string& news) {
44. latestNews = news;
45. notifyObservers(); // 뉴스 변경 시 알림
46. }
47. };
48.
49. // 4. ConcreteObserver (구체적인 옵저버/사용자)
50. class User : public Observer {
51. private:
52. string name;
53.
54. public:
55. User(const string& name) : name(name) {}
56.
57. void update(const string& news) override {
58. cout << name << " received news update: " << news << endl;
59. }
60. };
61.
62. // 5. Client (클라이언트 코드)
63. int main() {
64. NewsChannel channel;
65.
66. User user1("Alice");
67. User user2("Bob");
68.
69. channel.addObserver(&user1);
70. channel.addObserver(&user2);
71.
72. // 뉴스 발행 -> 모든 구독자(옵저버)에게 알림
73. channel.publishNews("Breaking News: New Observer Pattern Tutorial!");
74.
75. // user2 구독 취소
76. channel.removeObserver(&user2);
77.
78. // 새로운 뉴스 발행 -> user1만 알림 받음
79. channel.publishNews("Weather Update: It's going to rain tomorrow.");
80.
81. return 0;
82. }
83.
옵저버 패턴 장점
1. Subject는 Observer의 구체적인 구현을 몰라도 되며, 독립적으로 동작할 수 있음 = 느슨한 결합
2. 새로운 옵저버 추가하거나 제거할 때, Subject 코드 변경 필요 없음
3. 상태가 변경될 때만 옵저버들에게 알림을 주므로, 불필요한 업데이트 방지
옵저버 패턴 단점
1. Subject가 상태를 변경할 때, 모든 옵저버들에게 알림을 보내므로 성능 문제 발생할 수 있음
2. 이벤트 기반 구조이기 때문에, 어떤 옵저버가 언제 호출되는지 추적하기 어려움
'Unity > 디자인 패턴' 카테고리의 다른 글
| 디자인 패턴 (행위 패턴) - 전략 패턴 (Strategy Pattern) (0) | 2025.08.30 |
|---|---|
| 디자인 패턴 (행위 패턴) - 상태 패턴 (State Pattern) (0) | 2025.08.30 |
| 디자인 패턴 (행위 패턴) - 이터레이터 패턴 (Iterator Pattern) (0) | 2025.08.30 |
| 디자인 패턴 (행위 패턴) - 인터프리터 패턴 (Interpreter Pattern) (0) | 2025.08.30 |
| 디자인 패턴 (행위 패턴) - 커맨드 패턴 (Command Pattern) (0) | 2025.08.30 |