[Design Pattern] 옵저버(Observer) 패턴이란?
Design Pattern

[Design Pattern] 옵저버(Observer) 패턴이란?

728x90

 

 

옵저버 패턴(Observer pattern)은 데이터의 변경이 발생했을 경우 상대 클래스나 객체에 의존하지 않으면서 데이터 변경을 통보하고자 할 때 유용하다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다.

 

간단한 예제인 입력된 성적 값을 출력하는 프로그램을 작성해보자.

1. Observer

  • 추상화된 통보 대상 클래스
public interface Observer {
    /* 데이터의 변경을 통보했을 때 처리하는 메소드 */
    public abstract void update(); 
}

 

2. Subject

  • 추상화된 변경 관심 대상 데이터
public abstract class Subject {
    private List<Observer> observers = new ArrayList<Observer>();
  
    /* 통보 대상을 추가함 */
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    /* 통보 대상을 제거함 */
    public void detach(Observer observer) { 
        observers.remove(observer);
    }
  
    /* observers의 각 옵저버에게 변경을 통보함 */
    public void notifyObservers() {
        for(Observer o : observers) {
            o.update();
        }
    }
}

 

3. ScoreRecord

  • 구체적인 변경 감시 대상 데이터
  • ConcreteSubject라 칭한다.
public class ScoreRecord extends Subject {
    private List<Integer> scores = new ArrayList<Integer>();
  
    public void addScore(int score) {
        scores.add(score);
      
        /* 데이터가 변경되면 Subject 클래스의 notifyObservers 메서드를 호출해 */
        /* 각 옵저버에게 데이터의 변경을 통보함 */
        notifyObservers();
    }
  
    public List<Integer> getScoreRecord() {
        return scores;
    }
}

 

 

4. DataSheetView

  • Observer의 기능, 즉 update 메서드를 구현함으로써 통보 대상이 된다. ConcreteObserver라 칭한다.
  • DataSheetView 클래스는 ScoreRecord 클래스의 update 메서드를 호출해 출력할 점수를 구한다. 이때 DataSheetView 클래스의 update 메서드에서는 구한 점수 중에서 명시된 개수만큼의 점수만 출력한다.
public class DataSheetView implements Observer {
    private ScoreRecord scoreRecord;
    private int viewCount;
  
    public DataSheetView(ScoreRecord scoreRecord, int viewCount) {
        this.scoreRecord = scoreRecord;
        this.viewCount = viewCount;
    }
  
    /* 점수의 변경을 통보 받음 */
    public void update() {
        List<Integer> record = scoreRecord.getScoreRecord();
        displayScores(record, viewCount);
    }
  
    private void displayScores(List<Integer> record, int viewCount) {
        System.out.print("List of " + viewCount + " entries: ");
        for(int i = 0; i < viewCount && i < record.size(); i++) {
            System.out.print(record.get(i) + " ");
        }
        System.out.println();
    }
}

 

5. MinMaxView

  • DataSheetView 클래스와 마찬가지로 Observer의 기능을 구현한다. ConcreteObserver라 칭한다.
  • DataSheetView 클래스와 다르게 점수의 최소 / 최대 값만 출력한다.
public class MinMaxView implements Observer {
    private ScoreRecord scoreRecord;
  
    public MinMaxView(ScoreRecord scoreRecord) {
        this.scoreRecord = scoreRecord;
    }
  
    /* 점수의 변경을 통보 받음 */
    public void update() {
        List<Integer> record = scoreRecord.getScoreRecord();
        displayMinMax(record);
    }
  
    private void displayMinMax(List<Integer> record) {
        int min = Collections.min(record, null);
        int max = Collections.max(record, null);
      
        System.out.println("Min: " + min + " Max: " + max);
    }
}

 

 

Client 클래스에서는 성적을 저장하는 ScoreRecord 객체와 주어진 개수만큼의 점수만 출력하는 DataSheetView 객체, 최소/최대 값을 출력하는 MinMaxView 객체를 생성한다.

DataSheetView와 MinMaxView의 update 메서드가 실행될 때 ScoreRecord의 getScoreRecord 메서드를 호출되어야 한다. 따라서 ScoreRecord 객체를 DataSheetView와 MinMaxView의 생성자로 전달한다.

마지막으로 ScoreRecord는 점수가 추가될 때, DataSheetView와 MinMaxView의 update 메서드를 호출할 필요가 있다. 이를 위해 ScoreRecord의 attach 메서드를 호출해 DataSheetView와 MinMaxView를 전달한다.

public class Client {
    public static void main(String[] args) {
        ScoreRecord scoreRecord = new ScoreRecord();
        
        DataSheetView dataSheetView3 = new DataSheetView(scoreRecord, 3);
        MinMaxView minMaxView = new MinMaxView(scoreRecord);
      
        /* ScoreRecord에 Observer로 추가함 */
        scoreRecord.attach(dataSheetView3);
        scoreRecord.attach(minMaxView);
      
      	for (int i = 0; i <= 5; i++) {
            int score = i * 10;
            System.out.println("[+] adding " + score);
            
            /* 각 점수 추가 시 최대 3개 목록, 최소/최대 값을 출력함 */
            scoreRecord.addScore(score);
            System.out.println();
        }
    }
}

 

 

다음은 앞서 작성한 프로그램의 클래스 다이어그램이다.

 

옵저버 패턴은 통보 대상 객체의 관리를 Subject 클래스와 Observer 인터페이스로 일반화한다. 이렇게 하면 데이터 변경을 통보하는 클래스는 통보 대상 클래스나 객체에 대한 의존성을 없앨 수 있다. 결과적으로 옵저버 패턴은 통보 대상 클래스나 대상 객체의 변경에도 ScoreRecord 클래스를 수정 없이 그대로 사용할 수 있도록 한다.

 

출처 : JAVA 객체 지향 디자인 패턴 / 정인상, 채홍석

728x90