[Rust] Observer 패턴 구현하기

관련 포스트
https://blog.naver.com/sssang97/221705028470

Rust에서 옵저버 패턴을 구현하는 방법을 간략히 다뤄본다.
스레드를 별도로 띄우지 않는다면 옵저버 구현은 러스트에서도 쉽다.

먼저 구독자 역할을 할 옵저버에 대한 인터페이스를 정의한다.

update라는 메서드를 통해 변경사항을 전달받는다.


그리고 그 구현체다.
옵저버들이 각각 고유한 이름을 갖고, 갱신된 것을 전달받을때마다 복명복창을 하게 구현했다.

그리고 게시자(publisher) 역할을 할 Subject에 대한 인터페이스다.

register 메서드를 통해 알림을 보내줄 옵저버를 추가할 수 있고, notify를 통해 등록된 옵저버들에 알림을 보낸다.

그리고 그 구현례다.

내부적으로 카운트용 값과 옵저버 목록을 갖고, notify가 호출되면 현재값을 다 뿌려주도록 했다.


그리고 그 변경사항을 유발하는 메서드를 추가구현했다.

그러면 이런식으로 응용할 수 있을 것이다.

옵저버를 2개 등록했고, 증가 2번, 감소 1번을 했다.

그러면

이런식으로 구독자들이 변경사항을 전달받으면서 출력을 해줄 것이다.

여기서는 그냥 콘솔로그만 찍고 말았지만, 실 응용에서는 보디 많은 것을 할 것이다.

아래는 전체 코드다.

trait IObserver {
    fn update(&self, value: i32);
}

struct CounterObserver {
    observer_name: String,
}

impl IObserver for CounterObserver {
    fn update(&self, value: i32) {
        println!("Observer {} get: {value}", self.observer_name);
    }
}

trait ISubject {
    fn register(&mut self, observer: Box<dyn IObserver>);
    fn notify(&self);
}

struct CounterSubject {
    observers: Vec<Box<dyn IObserver>>,
    value: i32,
}

impl ISubject for CounterSubject {
    fn register(&mut self, observer: Box<dyn IObserver>) {
        self.observers.push(observer);
    }

    fn notify(&self) {
        for observer in &self.observers {
            observer.update(self.value);
        }
    }
}

impl CounterSubject {
    fn new() -> CounterSubject {
        CounterSubject {
            observers: Vec::new(),
            value: 0,
        }
    }

    fn increment(&mut self) {
        self.value += 1;
        self.notify();
    }

    fn decrement(&mut self) {
        self.value -= 1;
        self.notify();
    }
}

fn main() {
    let mut counter_subject = CounterSubject::new();

    let observer1 = CounterObserver {
        observer_name: "Observer 1".to_string(),
    };
    let observer2 = CounterObserver {
        observer_name: "Observer 2".to_string(),
    };

    counter_subject.register(Box::new(observer1));
    counter_subject.register(Box::new(observer2));

    counter_subject.increment();
    counter_subject.increment();
    counter_subject.decrement();
}