행위 패턴(Behavioral Patterns) | 옵저버(Observer) 패턴
[index]
1. 옵저버(Observer) 패턴이란?
2. 옵저버(Observer) 패턴의 장점
3. 옵저버(Observer) 패턴의 단점
4. 옵저버(Observer) 패턴 적용 예시
5. 마무리
+ 디자인 패턴이 무엇인지 모른다면?
https://reveur1996.tistory.com/149
1. 옵저버(Observer) 패턴이란?
옵서버(Observer) 패턴은 객체 간의 상호작용과 상태 변화에 관심이 있는 객체 집합(관찰자, observers)과 단일 객체(관찰 대상, observed) 간의 효과적인 상호작용을 정의하는 행위 디자인 패턴입니다. 이 패턴에서 관찰자들은 대상을 항상 관찰하지 않고, 대신 구독(subscribe)을 통해 변경 사항에 대한 알림을 받습니다. 주체 객체의 상태가 변경되면, 이를 구독한 모든 관찰자에게 자동으로 알림이 전달되어 상태 변경에 대한 처리를 수행할 수 있게 됩니다.
옵저버 패턴은 객체 간의 일 대 다(Dependents) 의존 관계를 정의하며, 주로 분산 이벤트 처리 시스템에서 활용됩니다. 다수의 컴포넌트들 간의 효율적인 통신을 허용하여 시스템을 유연하게 확장하고 관리할 수 있도록 도와줍니다.
옵저버 패턴의 구성 요소
- Subject(주체)
상태 변화를 알리고자 하는 대상 객체입니다. 일반적으로 하나 이상의 옵저버 객체를 등록하고, 상태가 변경될 때 이를 알립니다. - Observer(옵저버)
Subject의 상태를 감시하고 있는 객체로, 상태가 변경되었을 때 해당 변경을 처리하는 역할을 수행합니다. 하나의 Subject에 여러 Observer가 등록될 수 있습니다.
옵저버 패턴의 활용
- 분산 이벤트 핸들링
분산 환경에서 여러 컴포넌트 간의 이벤트 통지를 구현할 때, 옵저버 패턴은 중앙 이벤트 버스를 통해 효과적으로 활용됩니다. 이벤트 버스는 Subject 역할을 하고, 컴포넌트들은 Observer로 등록되어 이벤트를 수신합니다. - 모델-뷰-컨트롤러(MVC) 아키텍처
MVC 아키텍처에서 모델은 데이터의 상태를 나타내며, 뷰는 사용자에게 데이터를 표시하고, 컨트롤러는 사용자의 입력을 처리합니다. 모델의 상태 변경 시 뷰를 업데이트하는 부분에서 옵저버 패턴을 활용할 수 있습니다. - 구독(Publish-Subscribe) 시스템
브로커(Broker)를 통해 메시지를 발행하는 주체가 있고, 이를 구독하는 여러 옵저버가 있는 시스템에서 활용됩니다. 메시지가 발행되면 등록된 모든 옵저버에게 메시지가 전달되어 처리됩니다.
2. 옵저버(Observer) 패턴의 장점
- 느슨한 결합 (Loose Coupling)
주제(Subject)와 옵저버(Observer)는 서로 독립적으로 존재하며, 변경이 발생해도 서로에게 직접적인 영향을 미치지 않습니다. 이는 시스템의 유지보수성과 확장성을 향상시킵니다. - 재사용성과 확장성
새로운 옵저버를 추가하거나 기존의 옵저버를 변경하지 않고도 주제에 새로운 기능을 추가할 수 있습니다. 이로써 코드의 재사용성과 확장성이 높아집니다. - 이벤트 기반 프로그래밍
옵저버 패턴은 이벤트 기반 시스템에서 유용하게 활용됩니다. 주제에서 발생한 이벤트에 대응하여 여러 옵저버가 각자의 동작을 수행할 수 있습니다. - 분리된 관심사 (Separation of Concerns)
주제와 각각의 옵저버는 서로 독립적인 관심사를 가지고 있습니다. 주제는 상태 변경에 집중하고, 옵저버는 이 상태 변경에 대한 응답에 집중합니다. - 확장 가능한 이벤트 핸들링
여러 개의 옵저버가 동일한 이벤트에 반응할 수 있으며, 각각의 옵저버는 독립적으로 확장 가능한 이벤트 핸들링을 수행할 수 있습니다.
3. 옵저버(Observer) 패턴의 단점
- 메모리 누수 (Memory Leaks)
주제(Subject)가 옵저버(Observer)에 대한 참조를 갖고 있고, 옵저버가 명시적으로 제거되지 않는 경우 메모리 누수가 발생할 수 있습니다. 특히, 자바스크립트에서는 주제에서 옵저버에 대한 참조를 해제하는 것이 중요합니다. - 느리거나 비효율적인 업데이트
모든 옵저버는 주제의 상태가 변경될 때마다 업데이트됩니다. 만약 옵저버의 수가 많고, 각각의 업데이트 작업이 시간이 많이 걸린다면 성능 문제가 발생할 수 있습니다. - 불필요한 업데이트
옵저버 패턴에서는 주제의 상태가 변경되면 모든 옵저버에게 알려져야 합니다. 그 결과, 일부 옵저버는 실제로 상태 변경에 대해 관심이 없더라도 업데이트를 받게 될 수 있습니다. - 순서에 대한 제어 어려움
옵저버들이 동시에 상태를 업데이트할 때, 어떤 옵저버가 먼저 실행될지에 대한 제어가 어렵습니다. 따라서 옵저버 간의 순서를 정의하기 위해 추가적인 노력이 필요할 수 있습니다. - 보안 문제
주제와 옵저버 간의 직접적인 의존성 때문에, 보안 상의 문제가 발생할 수 있습니다. 특히, 옵저버가 주제의 중요한 정보에 직접 접근할 때 이를 방어하기 위한 추가적인 보안 처리가 필요할 수 있습니다.
4. 옵저버(Observer) 패턴 적용 예시
자바스크립트에서의 옵저버 패턴 | 프록시 객체를 통한 구현
프록시 객체는 어떠한 대상의 기본적인 동작의 작업을 가로챌 수 있는 객체를 뜻합니다. 자바스크립트에서 프록시 객체는 두 개의 매개 변수를 가집니다.
- target : 프록시할 대상
- handler : target 동작을 가로채고 어떠한 동작을 할 것인지가 설정되어 있는 함수
// 주제(Subject) 역할을 하는 클래스
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
// 옵저버(Observer) 역할을 하는 클래스
class Observer {
update(data) {
console.log(`Received update: ${data}`);
}
}
// 프록시 객체를 사용하여 주제와 옵저버 간의 중간 역할을 하는 클래스
class ObserverProxy {
constructor() {
this.subject = new Subject();
}
addObserver(observer) {
this.subject.addObserver(observer);
}
removeObserver(observer) {
this.subject.removeObserver(observer);
}
notify(data) {
console.log('Notifying observers...');
this.subject.notify(data);
}
}
// 테스트
const observer1 = new Observer();
const observer2 = new Observer();
const proxy = new ObserverProxy();
proxy.addObserver(observer1);
proxy.addObserver(observer2);
proxy.notify('Hello, observers!');
위 코드에서 Subject 클래스는 주제(Subject) 역할을 하며, Observer 클래스는 옵저버(Observer) 역할을 합니다. ObserverProxy 클래스는 프록시 역할을 하며, 실제 주제(Subject) 역할을 감싸고 있습니다. 이를 통해 주제와 옵저버 간의 느슨한 결합을 유지하면서도 중간에 프록시를 통해 제어할 수 있습니다.
5. 마무리
옵서버(Observer) 패턴은 객체 간의 상호작용과 상태 변화에 유연하게 대응할 수 있는 강력한 디자인 패턴 중 하나입니다. 이 패턴을 활용하면 객체들 간의 결합도를 낮추고, 변경에 대한 처리를 효율적으로 구현할 수 있습니다. 주체 객체의 상태 변화에 따라 동적으로 동작하는 시스템을 구축할 때 유용하게 활용됩니다. 옵저버 패턴은 분산 이벤트 처리 시스템에서의 효과적인 활용을 통해 다양한 컴포넌트들 간의 통신을 가능케하며, 시스템의 유연성과 확장성을 향상시킵니다. 이 패턴은 객체 지향 프로그래밍의 핵심 원칙 중 하나인 "의존성 역전 원칙(Dependency Inversion Principle)"을 잘 반영하여 시스템의 모듈성을 강화하고 유지보수성을 높입니다. 간결하면서도 효과적인 옵저버 패턴의 구현은 객체 지향 설계에 있어 유용한 도구 중 하나로, 변화에 대응하는 동적이고 모듈화된 소프트웨어 시스템을 구축하는 데 도움을 줍니다.
참고문헌
https://www.oreilly.com/library/view/learning-javascript-design/9781449334840/ch09s05.html
https://velog.io/@sehyunny/The-Observer-Pattern-in-JavaScript
https://www.dofactory.com/javascript/design-patterns/observer
https://www.patterns.dev/vanilla/observer-pattern/