Search

Chapter 9. 옵서버 패턴

생성일
2025/06/15 02:07
태그

옵서버 패턴

옵서버 패턴은 데이터의 변경이 발생했을 때 상대 클래스나 객체에 변경을 통보하는 경우에, 상대 클래스나 객체의 구체적인 구현을 의존하지 않고 변경사항을 통보하도록하여 상대 클래스나 객체의 변경이 발생해도 통보하는 클래스에서는 변경이 필요하지 않도록 하는 패턴이다.
하나의 예시로 차량의 연료 변화가 발생하면, 연료량 클래스에서 주행 가능 거리를 출력하는 클래스, 연료량 경고등 클래스 등에 변화를 통보한다. 이런 경우에는 직접 의존하지 않도록 설계하는 것이 옵서버 패턴이다.
Observer : 데이터의 변경을 통보 받는 인터페이스
Subject : Observer 인터페이스를 참조해서 ConcreteObserver에 변화를 통보하는 클래스
ConcreteObserver : 변경을 통보받는 클래스
이처럼 옵서버 패턴은 통보 대상 객체를 관리하는 Subject 클래스와 Observer 인터페이스로 일반화한다.
옵서버 패턴의 행위 모델을 순차 다이어그램으로 표현하면 이와 같다.

점수 출력하기

점수를 저장해두었다가 점수가 변경되면 출력하는 예시를 작성해보자.
public class ScoreRecord { private List<Integer> scores = new ArrayList<>(); private DataSheetView dataSheetView; public List<Integer> getScores() { return List.copyOf(scores); } public void setDataSheetView(final DataSheetView dataSheetView) { this.dataSheetView = dataSheetView; } public void addScore(final int score) { scores.add(score); dataSheetView.update(); } }
Java
복사
public class DataSheetView { private ScoreRecord scoreRecord; private int viewCount; public DataSheetView(final ScoreRecord scoreRecord, final int viewCount) { this.scoreRecord = scoreRecord; this.viewCount = viewCount; } public void update() { final List<Integer> scores = scoreRecord.getScores(); for (int i = 0; i < Math.min(scores.size(), viewCount); i++) { System.out.println(scores.get(i)); } } }
Java
복사
하지만 성적을 목록으로 출력하는게 아닌 최대/최소만 출력하고 싶다면? 혹은 여러 성적을 동시 혹은 순차적으로 출력하도록 변경한다면?
public class MinMaxSheetView { private ScoreRecord scoreRecord; public MinMaxSheetView(final ScoreRecord scoreRecord) { this.scoreRecord = scoreRecord; } public void update() { final List<Integer> scores = scoreRecord.getScores(); int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE; for (int i = 0; i < scores.size(); i++) { min = Math.min(min, scores.get(i)); max = Math.max(max, scores.get(i)); } System.out.println(min + " " + max); } }
Java
복사
public class ScoreRecord { private List<Integer> scores = new ArrayList<>(); private MinMaxSheetView minMaxSheetView; public List<Integer> getScores() { return List.copyOf(scores); } public void setMinMaxSheetView(final MinMaxSheetView minMaxSheetView) { this.minMaxSheetView = minMaxSheetView; } public void addScore(final int score) { scores.add(score); minMaxSheetView.update(); } }
Java
복사
이처럼 ScoreRecord의 변경이 발생하고 이는 OCP 설계 위반이다.
이를 옵서버 패턴을 통해 해결할 수 있다.
책의 예시와는 다르게 Subject가 불필요하다고 느껴 추상 클래스로 따로 분리하지 않음
public interface Observer { void update(); } public class DataSheetView implements Observer { // ... } public class MinMaxSheetView implements Observer { // ... }
Java
복사
public class ScoreRecord { private List<Integer> scores = new ArrayList<>(); private List<Observer> observers = new ArrayList<>(); public List<Integer> getScores() { return List.copyOf(scores); } public void attach(final Observer observer) { observers.add(observer); } public void detach(final Observer observer) { observers.remove(observer); } public void addScore(final int score) { scores.add(score); for (final Observer observer : observers) { observer.update(); } } }
Java
복사
이를 클래스 다이어그램으로 다음과 같다.