728x90
반응형
옵저버 패턴 (Observer Pattern)
옵저버 : 감시자, 관찰자
옵저버 패턴의 특징
- 관찰 중인 객체의 변화가 있을 때 마다 메서드를 통해 목록에 있는 옵저버(관찰자)들에게 이벤트를 알려주고 조치(메커니즘)를 취하는 디자인 패턴이다.
트위터, 유튜브, 인스타그램 처럼 팔로우(구독) 시스템이 있을 때 팔로우(구독)을 한다면 알림이 팔로워(구독자)들에게 전송된다.
옵저버 패턴은 MVC(Model-View-Controller) 패턴에서도 사용된다. ‘model() - 주체자’ 에서 변경 사항이 생기면 ‘view - 관찰자' 에 알리고 이를 통해 controller가 작동하는 원리이다.
옵저버 패턴의 장단점
장점
- 주체(Subject) 의 상태 변경을 주기적으로 조회하는 대신 자동으로 감지가 가능
- 주체(Subject)의 코드를 변경하지 않아도 관찰자(Observer) 클래스를 추가할 수 있어 개방 폐쇄 원칙(Open-Closed Principle) 을 준수한다.
- 런타임 시 이벤트(알림) 설정 가능
- 상태를 변경하는 주체와 변경을 감지하는 객체 사이의 느슨한 결합(인터페이스를 사용)을 통해 유연성을 확보할 수 있음
단점
- 관찰자는 알림 순서 제어가 불가능하고 알림은 무작위로 전달될 수 있음
➡️ 순서를 제어하게 되면 복잡성, 결합성이 높아진다. 다른 알림을 처리 하기 전, 후에 알림을 먼저 받아야 하는데 그렇게 되면 옵저버들 사이에 순서와 의존성이 생기게 된다. 이는 옵저버가 독립적으로 작동하는 기본 원칙을 위반하게 되는 것이다. - 옵저버 패턴의 사용이 많아지면 구조와 동작 파악이 어려워 코드의 복잡성 증가
- 메모리 누수 발생 위험 (옵저버 객체 해지를 안 했을 때) (예시, 매장에서는 새로운 제품이 출시될 때 마다 모든 고객에게 이메일을 보내는데 매일을 받고 싶지 않은 사람들은 알림창 자원 낭비)
옵저버 패턴 구조
Subject
- 주체자를 정의하는 인터페이스 구현
- Observer 관리하기 위한 내부 리스트(List, Map, Set) - 합성하여 가짐
- Observer를 등록하거나 삭제하기 위한 메서드(register , remove ) 제공
- 상태 변경이나 특정 동작이 발생할 때 모든 Observer 에게 알리는 notify 기능
Observer
- 관찰자를 정의하는 인터페이스 구현
- Subject로 부터 알림을 받으면 상태 변경에 대해 반응
- Subject의 상태 업데이트에 따른 처리로직 구현
사용자 인터페이스(UI) 요소가 어플리케이션의 상태 변화에 따라 업데이트되어야 하는 경우나, 여러 서비스가 특정 이벤트에 반응해야 할 때 유용하다.
예시
Subject 인터페이스
package observer;
// 관찰자 , 대상자
public interface Subject {
public void register(Observer obj);
public void unregister(Observer obj);
public void notifyObserver();
public Object getUpdate(Observer obj);
}
Topic 클래스
- Topic 클래스를 통해 Subject 인터페이스를 구현
- topic 이 주체이자 객체가 된다.
package observer;
import java.util.ArrayList;
import java.util.List;
public class Topic implements Subject {
// 관찰자들을 등록하여 담는 리스트
private List<Observer> observers;
private String message;
public Topic() {
this.observers = new ArrayList<>();
this.message = "";
}
// 관찰자를 리스트에 등록
@Override
public void register(Observer obj) {
if(!observers.contains(obj)) observers.add(obj);
}
// 관찰자를 리스트에서 제거
@Override
public void unregister(Observer obj) {
observers.remove(obj);
}
// 관찰자에게 이벤트 알림
@Override
public void notifyObserver() {
// 리스트 순회
this.observers.forEach(Observer::update);
}
// 업데이트(위임)
@Override
public Object getUpdate(Observer obj) {
return this.message;
}
public void postMessage(String msg) {
System.out.println("Message sended to Topic : " + msg);
this.message = msg;
notifyObserver();
}
}
Observer 인터페이스
package observer;
// 관찰자, 구독자
public interface Observer {
public void update();
}
TopicSubscriber 클래스
package observer;
public class TopicSubscriber implements Observer {
private String name;
private Subject topic;
public TopicSubscriber(String name, Subject topic) {
this.name = name;
this.topic = topic;
}
@Override
public void update() {
String msg = (String) topic.getUpdate(this);
System.out.println(name + ":: got message >> " + msg);
}
}
HelloWorld 클래스
- 옵저버 선언 시 이름과 어떠한 토픽의 옵저버가 될 것인지 정함
package observer;
public class HelloWorld {
public static void main(String[] args) {
// 발행자 등록
Topic topic = new Topic();
// 발행자를 구독할 관찰자 리스트로 등록
Observer a = new TopicSubscriber("a", topic);
Observer b = new TopicSubscriber("b", topic);
Observer c = new TopicSubscriber("c", topic);
// 관찰자에게 이벤트 전파
topic.register(a);
topic.register(b);
topic.register(c);
// 구독 취소
topic.unregister(b);
// 관찰자(구독자)에게만 메세지(알림 전송)
topic.postMessage("amumu is op champion .");
/*
Message sended to Topic : amumu is op champion .
a:: got message >> amumu is op champion .
c:: got message >> amumu is op champion .
*/
}
}
참고자료 📖
728x90
반응형
'KNOWLEDGE' 카테고리의 다른 글
[디자인 패턴] 싱글톤 패턴 (Singleton Pattern) - 자바 예제 (1) | 2024.04.15 |
---|---|
[OS] 페이징, PTBR, TLB(Translation Lookaside Buffer, 변환색인 버퍼) 란 무엇인가? (0) | 2023.12.14 |
[OS] 시스템 호출(System call) & 운영체제 - 커널모드(Kernerl Mode)와 사용자 모드(User Mode) (0) | 2023.11.17 |
[NETWORK] REST API, RESTful 알아보기 / REST란? (1) | 2023.11.16 |
[OS] CPU 스케줄링 알고리즘 / 프로그램 vs 프로세스 vs 스레드 (2) | 2023.11.08 |