본문 바로가기
IT/Design Pattern

Observer Pattern

by how-are-you 2024. 5. 15.

Observer : 관찰자, 감시자라는 의미입니다.

 

어떠한 값을 관리하고 이에 대한 알람 값을 받고 싶습니다. 이에 대한 로직을 구현할 때, 관리를 하는 측에서는 데이터가 자동으로 업데이트 됩니다. 

 

자율 주행 자동차를 예시로 사용을 해봅니다. 

테슬라의 Model X에서는 하나의 칩에서 브레이크, 미터기의 현재 속도, 차량과의 거리 정보들을 알림받고 싶습니다. 

그럼 자동차의 main CPU 에서는 각각의 값을 받아야 합니다. 이에 대한 구현을 어떻게 하면 좋을까요?

 

먼저 class를 짜봅니다.

1. MainComputer : 알람 받을 곳, Meter와 Camera, Break에서 데이터가 변동되면 받아야 함. 

2. Meter: 알람 주는 객체 1. 데이터가 변할 시 알람을 줌

3. Camera: 알람 주는 객체 2. 데이터가 변할 시 알람을 줌

4. Break: 알람 주는 객체 3. 데이터가 변할 시 알람을 줌

5. Subject: Observer들을 가지고 있으며 알람을 줄 곳을 등록하는 class. 알람을 주는 곳에서 이 클래스를 상속함. 알람 등록 및 제거 및 알림 기능이 있음

6. Observer: 알람을 받을 클래스에서 이 클래스를 상속하며 데이터 업데이트함

 

observer 패턴의 클래스 다이아그램은 다음과 같습니다.

class diagram

위에서 데이터를 set하는 함수, 데이터가 변경되는 함수가 추가로 구현되어야 합니다. 

위와 같은 형태로 observer와 subject를 짜서 상속하는 구조로 만들면 각각의 모듈에서 알람을 받을 곳을 attach로 등록만 해놓고, 모듈에서 notify함수만 불러준다면 이 정보를 MainComputer에서 알 수 있습니다. 

 

 

아래는 위 클래스다이어그램을 참고하여 함수를 추가하여 만든 코드입니다.

 

#include <iostream>
#include <vector>
#include <string>

// Observer 인터페이스
class Observer {
public:
    virtual void update(const std::string& data) = 0;
};

// Subject 클래스
class Subject {
private:
    std::vector<Observer*> observers;

public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }

    void detach(Observer* observer) {
        // observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
        for(auto it = observers.begin(); it != observers.end(); ++it) {
            if(*it == observer) {
                observers.erase(it);
                break;
            }
        }
    }

    void notify(const std::string& data) {
        for(auto observer : observers) {
            observer->update(data);
        }
    }
};

// MainComputer 클래스 (Observer)
class MainComputer : public Observer {
public:
    void update(const std::string& data) override {
        std::cout << "MainComputer received data: " << data << std::endl;
    }
};

// Meter 클래스 (Subject)
class Meter : public Subject {
private:
    int speed;

public:
    void setSpeed(int speed) {
        this->speed = speed;
        notify("Speed: " + std::to_string(speed));
    }
};

// Camera 클래스 (Subject)
class Camera : public Subject {
public:
    void captureImage() {
        // Capture image logic here
        std::string imageData = "Image data";
        notify("Image: " + imageData);
    }
};

// Brake 클래스 (Subject)
class Brake : public Subject {
public:
    void checkBrakeStatus() {
        // Check brake status logic here
        std::string brakeStatus = "Brake status";
        notify("Brake: " + brakeStatus);
    }
};

int main() {
    // 객체 생성
    MainComputer mainComputer;
    Meter meter;
    Camera camera;
    Brake brake;

    // MainComputer를 각 클래스의 Observer로 등록
    meter.attach(&mainComputer);
    camera.attach(&mainComputer);
    brake.attach(&mainComputer);

    // 시뮬레이션: 정보가 업데이트되면 MainComputer에게 알림
    meter.setSpeed(60);
    camera.captureImage();
    brake.checkBrakeStatus();

    return 0;
}

 

'IT > Design Pattern' 카테고리의 다른 글

Singleton Pattern(feat. Logger)  (0) 2024.05.18
Factory pattern  (0) 2024.05.12