Reactive Programming
- 데이터의 흐름에서 발생하는 변화에 효율적이고 유연한 대응을 제공
- 이벤트 기반의 Application을 보다 간편하게 구현할 수 있는 프로그래밍
리액티브 프로그래밍의 기본 원칙
1. 옵저버블과 옵저버 패턴 (Observable and Observer Pattern):
옵저버 패턴(Observer Pattern)
- 객체 간에 일대다(one to many) 의존성을 정의하는 디자인 패턴.
- 분산 이벤트 핸들링 시스템에서 사용
- 동작 방식: A객체의 상태가 변경되면 A객체에 의존하는 다른 객체들에게 알림이 간 후, 자동으로 내용이 갱신되는 방식.
- 구성
- Subject(이벤트 발행자, 주체):
- 상태 변화를 감시하고 있는 객체
- 옵저버들의 목록을 유지하고 각 옵저버에게 상태 변화를 알림
- Observer(옵저버)
- 주체의 상태 변화를 감지하고, 이에 대응하여 동작을 수행하는 객체
- 주체에 등록되어있어야하며, 주체의 알림에 응답함.
- 장점
- 주체와 옵저버의 느슨한 결합으로 인한 유지보수가 쉬움
- 새로운 옵저버를 추가하기 쉬움
- 이벤트 기반 시스템에서 유용하게 사용
- 예제
protocol Observer: AnyObject {
func update(data: Any)
}
class Subject {
private var observers: [Observer] = []
private var data: Any?
func addObserver(_ observer: Observer) {
observers.append(observer)
}
func removeObserver(_ observer: Observer) {
observers = observers.filter { $0 !== observer }
}
func notifyObservers() {
for observer in observers {
observer.update(data: data)
}
}
func setData(_ data: Any) {
self.data = data
notifyObservers()
}
}
class ConcreteObserver: Observer {
private let name: String
init(name: String) {
self.name = name
}
func update(data: Any) {
print("\(name) received an update: \(data)")
}
}
let subject = Subject()
let observer1 = ConcreteObserver(name: "Observer 1")
let observer2 = ConcreteObserver(name: "Observer 2")
subject.addObserver(observer1)
subject.addObserver(observer2)
subject.setData("New Data 1")
subject.removeObserver(observer1)
subject.setData("New Data 2")
옵저버블(Observable)
- 리액티브 프로그로밍에서 사용되는 개념으로 데이터 스트림이나 이벤트 스트림을 나타냄.
- 이벤트 스트림: 시간에 따라 발생하는 이벤트의 연속적인 흐름을 의미. 시스템 내에서 발생하는 다양한 상황과 상호작용을 나타내며 이러한 이벤트들이 연속적으로 발생하여 스트림을 형성.
- 연속성: 시간에 따라 연속적으로 발생하며, 새로운 이벤트는 이전 이벤트의 뒤를 이어 발생.
- 다양성: 다양한 종류의 이벤트를 포함(사용자의 입력, 센서 데이터, 네트워크 이벤트 등)
- 비동기적 발생: 비동기적으로 발생하며 시스템의 여러 부분에서 동시 발생할 수 있음.
- 데이터 스트림의 표현: 시간적으로 순서가 있는데이터로 간주
- 데이터 스트림: 시간의 흐름에 따라 생산되고 소비되는 데이터의 흐름을 의미
- 연속성: 지속적으로 발생하는 데이터의 흐름
- 비동기성: 비동기적으로 발생하여 생산과 소비가 동시에 이루어질 수 있음.
- 이벤트 기반: 이벤트 기반의 프로그래밍에서 사용
- 무한성: 무한한 데이터를 생성할 수 있음
- 스트림 처리를 통해 다양한 작업을 수행할 수 있음 (데이터의 변형, 필터링, 집계, 합류 등)
- 위의 두개의 차이를 보면 둘다 시간에 따라 발생하였지만 이벤트 스트림은 이벤트 흐름을 나타낸 것이고, 데이터 스트림은 이벤트에서 발생한 데이터의 흐름이다.
(이벤트 스트림: 이벤트의 연속, 데이터 스트림: 데이터의 연속)
- 구성:
- Observable(옵저버블):
- 데이터의 생성 및 변화를 담당하는 객체
- 이벤트 스트림을 통해 데이터를 옵저버에게 전달
예시) "데이터가 옵저버에게 전달된 것"이라는 상황은 옵저버블이 생성한 데이터 스트림에서 이벤트가 발생하여 그 데이터가 옵저버에게 전달되는 것을 의미한다. 이때, 이벤트 스트림을 통해 전달되는 데이터는 데이터 스트림이라고 할 수 있다.
- Observer(옵저버):
- 옵저버 패턴의 옵저버와 유사하게 옵저버블에서 생성된 이벤트나 데이터 스트림의 변화를 감지하고 처리하는 객체
- 장점:
- 비동기적인 이벤트 처리를 쉽게 구현할 수 있음.
- 데이터의 연속적인 변화를 다루기 적합(데이터 스트림 처리)
- 리액티브 프로그래밍 패러다임을 구현하는데 사용
- 예제: 옵저버블 패턴을 구현하기 위해 RxSwift나 Combine과 같은 라이버리를 사용
import RxSwift
let observable = Observable<String>.create { observer in
DispatchQueue.global().async {
observer.onNext("Event 1")
observer.onNext("Event 2")
observer.onNext("Event 3")
observer.onCompleted()
}
return Disposables.create()
}
let observer = observable.subscribe(
onNext: { event in
print("Received event: \(event)")
},
onCompleted: {
print("Observable completed")
}
)
observer.dispose()
2. 비동기성 (Asynchrony):
- 비동기적인 프로그래밍을 강조
(여러 작업을 동시에 처리하거나, 한 작업이 완료될 때까지 다른 작업을 차단하지 않고 진행)
3. 데이터 스트림 (Data Streams):
- 데이터의 연속적인 흐름에 중점을 둡니다.
(시간에 따른 데이터의 변화를 스트림으로 표현하고, 이를 통해 데이터의 흐름에 대응)
4. 변화의 전파 (Change Propagation):
- 시스템의 상태가 변할 때, 이에 연결된 다른 부분에 자동으로 변경을 전파하여 동기화
(데이터 바인딩이나 옵저버 패턴과 관련)
- 데이터 바인딩: 두 개 이상의 변수 또는 속성을 연결하여 한쪽의 변경이 다른 쪽에 자동으로 반영되도록 하는 기술.
예시) A 변수와 B 변수를 양방향으로 바인딩한다고 가정해 봅시다. 이 경우, A의 값이 변경되면 B도 자동으로 해당 변경 사항을 반영하고, 반대로 B의 값이 변경되면 A도 업데이트
5. 함수형 프로그래밍의 영향 (Functional Programming):
- 함수형 프로그래밍의 원칙을 따름.
(불변성과 순수 함수를 통해 예측 가능하고 테스트 가능한 코드를 작성)
6. 반응형 시스템 (Reactive Systems):
- 반응형 시스템을 구축.
(탄력성을 가지며, 실패에 대응할 수 있는 시스템)