옵서버 패턴은 일부 객체들이 다른 객체들에 자신의 상태 변경에 대해 알릴 수 있는 행동 디자인 패턴입니다.
옵서버 패턴은 구독자 인터페이스를 구현하는 모든 객체에 대한 이러한 이벤트들을 구독 및 구독 취소하는 방법을 제공합니다.
복잡도:
인기도:
사용 사례들: 옵서버 패턴은 자바 코드, 특히 그래픽 사용자 인터페이스 컴포넌트들에서 매우 일반적입니다. 다른 객체들과의 클래스들과 결합하지 않고 해당 객체들에서 발생하는 이벤트들에 반응하는 방법을 제공합니다.
다음은 코어 자바 라이브러리로부터 가져온 패턴의 몇 가지 예시들입니다:
식별: 옵서버 패턴은 들어오는 메서드들을 목록에 저장하는 구독 메서드로 초기 식별할 수 있으며, 만약 위 구독 메서드가 목록의 객체들을 순회하고 그들의 '업데이트' 메서드를 호출하면 해당 패턴은 옵서버 패턴으로 확정지을 수 있습니다.
이벤트 구독
이 예시에서 옵서버 패턴은 텍스트 편집기의 객체 간의 간접적인 협업을 설정합니다. Editor
(편집기) 객체가 변경될 때마다 해당 객체는 그의 구독자들을 알립니다. EmailNotificationListener
및 LogOpenListener
는 그들의 기초 행동들을 실행하여 이러한 알림들에 반응합니다.
구독자 클래스들은 편집기 클래스에 결합하지 않으며 필요한 경우 다른 앱에서 재사용될 수 있습니다. 편집기
클래스는 오로지 추상 구독자 인터페이스에만 의존합니다. 이렇게 하면 편집기의 코드를 변경하지 않고도 새 구독자 유형들을 추가할 수 있습니다.
publisher publisher/EventManager.java: 기초 게시자
package refactoring_guru.observer.example.publisher;
import refactoring_guru.observer.example.listeners.EventListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EventManager {
Map<String, List<EventListener>> listeners = new HashMap<>();
public EventManager(String... operations) {
for (String operation : operations) {
this.listeners.put(operation, new ArrayList<>());
}
}
public void subscribe(String eventType, EventListener listener) {
List<EventListener> users = listeners.get(eventType);
users.add(listener);
}
public void unsubscribe(String eventType, EventListener listener) {
List<EventListener> users = listeners.get(eventType);
users.remove(listener);
}
public void notify(String eventType, File file) {
List<EventListener> users = listeners.get(eventType);
for (EventListener listener : users) {
listener.update(eventType, file);
}
}
}
editor editor/Editor.java: 다른 객체들로 추적된 구상 게시자
package refactoring_guru.observer.example.editor;
import refactoring_guru.observer.example.publisher.EventManager;
import java.io.File;
public class Editor {
public EventManager events;
private File file;
public Editor() {
this.events = new EventManager("open", "save");
}
public void openFile(String filePath) {
this.file = new File(filePath);
events.notify("open", file);
}
public void saveFile() throws Exception {
if (this.file != null) {
events.notify("save", file);
} else {
throw new Exception("Please open a file first.");
}
}
}
listeners listeners/EventListener.java: 공통 옵서버 인터페이스
package refactoring_guru.observer.example.listeners;
import java.io.File;
public interface EventListener {
void update(String eventType, File file);
}
listeners/EmailNotificationListener.java: 알림 수신 시 이메일 전송
package refactoring_guru.observer.example.listeners;
import java.io.File;
public class EmailNotificationListener implements EventListener {
private String email;
public EmailNotificationListener(String email) {
this.email = email;
}
@Override
public void update(String eventType, File file) {
System.out.println("Email to " + email + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
}
}
listeners/LogOpenListener.java: 알림 수신 시 로그에 메시지를 씁니다
package refactoring_guru.observer.example.listeners;
import java.io.File;
public class LogOpenListener implements EventListener {
private File log;
public LogOpenListener(String fileName) {
this.log = new File(fileName);
}
@Override
public void update(String eventType, File file) {
System.out.println("Save to log " + log + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
}
}
Demo.java: 초기화 코드
package refactoring_guru.observer.example;
import refactoring_guru.observer.example.editor.Editor;
import refactoring_guru.observer.example.listeners.EmailNotificationListener;
import refactoring_guru.observer.example.listeners.LogOpenListener;
public class Demo {
public static void main(String[] args) {
Editor editor = new Editor();
editor.events.subscribe("open", new LogOpenListener("/path/to/log/file.txt"));
editor.events.subscribe("save", new EmailNotificationListener("admin@example.com"));
try {
editor.openFile("test.txt");
editor.saveFile();
} catch (Exception e) {
e.printStackTrace();
}
}
}
OutputDemo.txt: 실행 결과
Save to log \path\to\log\file.txt: Someone has performed open operation with the following file: test.txt
Email to admin@example.com: Someone has performed save operation with the following file: test.txt