부모자식 클래스 간 비동기 데이터 통신
Observer 패턴을 활용한 클래스 간 비동기 데이터 통신방법
개요
인터페이스를 관리하는 클래스에서 데이터나 상태를 비동기 방식으로 상위 클래스 또는 다른 모듈로 전달해야 하는 경우가 있다.
예를 들어, 시리얼 통신이나 TCP 통신을 관리하는 클래스가 존재할 때,
- Low-level 인터페이스를 담당하는 클래스에서 다른 장비로부터 데이터 수신
- 비즈니스 로직(데이터 가공 등)을 담당하는 상위 클래스로 전달
이러한 구조에서는 Observer 패턴을 활용할 수 있으며, 이를 콜백(callback) 기반의 이벤트 리스너 기법을 활용하여 구현할 수 있다.
Observer 패턴은 데이터를 제공하는 주체(Subject)가 하나 이상의 구독자(Observer)에게 상태 변경을 통지하는 방식을 의미하며, 이벤트 리스너는 Observer 패턴을 구현하는 한 가지 방법이다.
| 항목 | 이벤트 리스너 | Observer 패턴 |
|---|---|---|
| 주요 개념 | 특정 이벤트 발생 시 미리 등록한 리스너(콜백 함수)를 실행 | 객체의 상태 변화를 감지하고, 구독자(Observer)에게 자동으로 알림 |
| 실행 방식 | 이벤트가 발생하는 특정 객체에서 등록된 핸들러를 실행 | Observer가 Subject를 구독하면, Subject의 상태가 변경될 때 알림 |
| 구현 | 콜백 함수를 이벤트에 직접 등록 (예: addEventListener) | Subject와 Observer 클래스를 정의하여 관계를 설정 |
장점
- 비동기 데이터 처리 가능: 데이터가 도착했을 때만 처리하므로 불필요한 CPU 리소스 소모를 방지
- 느슨한 결합(loose coupling): 통신 클래스와 상위 모듈이 직접 연결되지 않고, 인터페이스를 통해 유연하게 결합
- 확장성 증가: 다른 프로토콜이나 처리 방식이 필요할 경우 새로운 이벤트 리스너를 추가하여 쉽게 확장
예시
C++을 이용하여 예시 코드를 작성하였다. 아래 링크에서 전체를 확인할 수 있다.
https://github.com/grade-e/event-listener-cpp-container
DataSource에서 데이터, 상태를 생성할 경우에 callback 메서드 구현- data_callback_
- state_callback_
MyNode에서DataSource의 callback에 대응하는 메서드 등록- 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.