Post

부모자식 클래스 간 비동기 데이터 통신

Observer 패턴을 활용한 클래스 간 비동기 데이터 통신방법

개요

인터페이스를 관리하는 클래스에서 데이터나 상태를 비동기 방식으로 상위 클래스 또는 다른 모듈로 전달해야 하는 경우가 있다.

예를 들어, 시리얼 통신이나 TCP 통신을 관리하는 클래스가 존재할 때,

  1. Low-level 인터페이스를 담당하는 클래스에서 다른 장비로부터 데이터 수신
  2. 비즈니스 로직(데이터 가공 등)을 담당하는 상위 클래스로 전달

이러한 구조에서는 Observer 패턴을 활용할 수 있으며, 이를 콜백(callback) 기반의 이벤트 리스너 기법을 활용하여 구현할 수 있다.

Observer 패턴은 데이터를 제공하는 주체(Subject)가 하나 이상의 구독자(Observer)에게 상태 변경을 통지하는 방식을 의미하며, 이벤트 리스너는 Observer 패턴을 구현하는 한 가지 방법이다.

항목이벤트 리스너Observer 패턴
주요 개념특정 이벤트 발생 시 미리 등록한 리스너(콜백 함수)를 실행객체의 상태 변화를 감지하고, 구독자(Observer)에게 자동으로 알림
실행 방식이벤트가 발생하는 특정 객체에서 등록된 핸들러를 실행Observer가 Subject를 구독하면, Subject의 상태가 변경될 때 알림
구현콜백 함수를 이벤트에 직접 등록 (예: addEventListener)SubjectObserver 클래스를 정의하여 관계를 설정

장점

  • 비동기 데이터 처리 가능: 데이터가 도착했을 때만 처리하므로 불필요한 CPU 리소스 소모를 방지
  • 느슨한 결합(loose coupling): 통신 클래스와 상위 모듈이 직접 연결되지 않고, 인터페이스를 통해 유연하게 결합
  • 확장성 증가: 다른 프로토콜이나 처리 방식이 필요할 경우 새로운 이벤트 리스너를 추가하여 쉽게 확장

예시

C++을 이용하여 예시 코드를 작성하였다. 아래 링크에서 전체를 확인할 수 있다.

https://github.com/grade-e/event-listener-cpp-container

  • DataSource에서 데이터, 상태를 생성할 경우에 callback 메서드 구현
    • data_callback_
    • state_callback_
  • MyNode에서 DataSourcecallback에 대응하는 메서드 등록
    • onDataChanged
    • onStateChanged

Class diagram

classDiagram
    class DataSource {
        - DataCallback data_callback_
        - StateCallback state_callback_
        + void registerDataCallback(DataCallback cb)
        + void registerStateCallback(StateCallback cb)
        + void generateData(const std::string& data)
        + void updateState(int state)
    }

    class MyNode {
        - DataSource& data_source_
        + MyNode(DataSource& ds)
        - void onDataReceived(const std::string& data)
        - void onStateChanged(int state)
    }

    MyNode --> DataSource : "Registers Callbacks"

코드

Class: DataSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// DataSource 클래스 정의
class DataSource {
private:
    std::function<void(const std::string&)> data_callback_;  // 데이터 콜백
    std::function<void(int)> state_callback_;  // 상태 콜백

public:
    // 데이터 수신 콜백 등록
    void registerDataCallback(std::function<void(const std::string&)> cb) {
        data_callback_ = cb;
    }

    // 상태 변경 콜백 등록
    void registerStateCallback(std::function<void(int)> cb) {
        state_callback_ = cb;
    }

    // 데이터 발생 (예제에서는 1초마다 호출)
    void generateData(const std::string& data) {
        if (data_callback_) {
            data_callback_(data);
        }
    }

    // 상태 변경 (예제에서는 상태 변경 후 호출)
    void updateState(int state) {
        if (state_callback_) {
            state_callback_(state);
        }
    }
};

Class: MyNode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class MyNode {
private:
    DataSource& data_source_;

public:
    MyNode(DataSource& ds) : data_source_(ds) {
        // 콜백 등록
        data_source_.registerDataCallback([this](const std::string& data) {
            onDataReceived(data);
            });

        data_source_.registerStateCallback([this](int state) {
            onStateChanged(state);
            });
    }

    // 데이터가 들어왔을 때 실행될 콜백
    void onDataReceived(const std::string& data) {
        std::cout << "[MyNode] Received Data: " << data << std::endl;
    }

    // 상태 변경 시 실행될 콜백
    void onStateChanged(int state) {
        std::cout << "[MyNode] State Changed: " << state << std::endl;
    }
};

실행 결과

DataSource에서 발생한 두 개의 이벤트를 MyNode에서 각각 순차적으로 수신하여 출력

1
2
3
4
[MyNode] Received Data: Hello, World!
[MyNode] State Changed: 1
[MyNode] Received Data: Another Message
[MyNode] State Changed: 2
This post is licensed under CC BY 4.0 by the author.