본문 바로가기

IT/디자인 패턴(Design Pattern)

[디자인 패턴] 옵저버 패턴(Observer Pattern)

1) 개요

옵저버 패턴은 객체의 상태 변화를 관찰하는 관찰자 객체를 생성하여 사용하는 디자인 패턴입니다.

즉, 객체의 변화가 발생하면 그에 따르는 종속객체들이 자동으로 변화가 통지되어 그에 따른 명령을 수행하도록하는 일대다의 의존성을 정의해줍니다.


- 옵저버 패턴을 사용하는 경우
1. 분산 이벤트 핸들링 시스템 
2. 이벤트 기반 프로그래밍

- 장점
1. 객체간의 결합도가 느슨해집니다.
2. 실시간으로 효과적으로 데이터를 배분할 수 있습니다.

- 단점
1. 패턴을 잘못 구현할 경우 데이터 배분에 문제가 발생하여 위험도가 큽니다.

2) UML


3) 예제

1
2
3
4
public interface Observer {
    public void update(int runs, int wickets, float overs);
}
 
cs

1
2
3
4
5
6
public interface Subject {
    public void registerObserver(Observer o);
    public void unregisterObserver(Observer o);
    public void notifyObservers();
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AverageScoreDisplay implements Observer {
 
    private float runRate;
    private int predictedScore;
    
    @Override
    public void update(int runs, int wickets, float overs) {
        this.runRate = (float)runs/overs;
        this.predictedScore = (int)(this.runRate * 50);
        display();
    }
    
    public void display() {
        System.out.println("\nAverage Score Display : " +
                           "\nRun Rate : " + runRate + 
                           "\nPredictedScore : " + predictedScore);
    }
 
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CurrentScoreDisplay implements Observer{
    
    private int runs, wickets;
    private float overs;
    
    @Override
    public void update(int runs, int wickets, float overs) {
        this.runs = runs;
        this.wickets = wickets;
        this.overs = overs;
        display();
    }
    
    public void display() {
        System.out.println("\nCurrent Score Display : " +
                            "\nRuns: " + runs + 
                            "\nWickets:" + wickets + 
                            "\nOvers: " + overs ); 
    }
 
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class CircketData implements Subject{
 
    int runs;
    int wickets;
    float overs;
    ArrayList<Observer> observerList;
    
    public CircketData() {
        observerList = new ArrayList<Observer>();
    }
    
    @Override
    public void registerObserver(Observer o) {
        observerList.add(o);
    }
 
    @Override
    public void unregisterObserver(Observer o) {
        observerList.remove(observerList.indexOf(o));
    }
 
    @Override
    public void notifyObservers() {
        for (Iterator<Observer> it = observerList.iterator(); it.hasNext();) {
            Observer o = it.next();
            o.update(runs, wickets, overs);
        }
    }
 
    private int getLatestRuns() {
        return 90;
    }
    
    private int getLatestWickets() {
        return 2;
    }
    
    private float getLatestOvers() {
        return (float)10.2;
    }
    
    public void dataChanged() {
        runs = getLatestRuns();
        wickets = getLatestWickets();
        overs = getLatestOvers();
        
        notifyObservers();
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main {
    public static void main(String[] args) {
        AverageScoreDisplay averageScoreDisplay = 
                    new AverageScoreDisplay();
        CurrentScoreDisplay currentScoreDisplay = 
                    new CurrentScoreDisplay();
        CircketData circketData = new CircketData();
        circketData.registerObserver(averageScoreDisplay);
        circketData.registerObserver(currentScoreDisplay);
        
        circketData.dataChanged();
        
        System.out.println("\n--------- Remove AverageScoreDisplay ---------");
        circketData.unregisterObserver(averageScoreDisplay);
        circketData.dataChanged();
    }
}
 
cs