옵저버 패턴
하나의 객체(서브젝트)가 변할 때, 자동으로 다른 여러 객체들(오브젝트)에게 영향을 동적으로 반영하는 일대다 관계 패턴
이때 여러 오브젝트가 추가 될 수 있어야 한다.
배울 내용 요약
1. 서로 상호작용하는 객체들은 느슨하게 연결되어야 한다.
예제로 알아보자.
NBA사무국에서는 선수들의 정보를 관리하고 있다.
NBA방송국 NBC, TNT에서는 이 정보를 받아 방송하고 있다.
선수들의 정보가 변하게 될 때, 이 두 방송국에서 자동으로 정보를 바꾸고, 바뀐 정보를 방송하는 프로그램을 만들어보자.
일단 방송국들이 반영할 사무국에 대한 인터페이스를 만들어보자
1 2 3 4 5 6 7
| package Observer;
public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); }
|
방송국들의 인터페이스도 만들어주자.
1 2 3 4 5
| package Observer;
public interface Observer { public void update(float ppg, float rpg, float apg); }
|
사무국의 인터페이스를 기반으로 사무국 클래스를 만들어보자.
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
| package Observer;
import java.util.ArrayList;
public class NBAData implements Subject{ private ArrayList observers; private float ppg; private float rpg; private float apg;
public NBAData(){ observers = new ArrayList(); }
public void registerObserver(Observer o){ observers.add(o); } public void removeObserver(Observer o){ int i = observers.indexOf(o); if (i >= 0){ observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++){ Observer observer = (Observer)observers.get(i); observer.update(ppg, rpg, apg); } } public void measurementChanged(){ notifyObservers(); } public void setMeasurements(float ppg, float rpg, float apg){ this.ppg = ppg; this.apg = apg; this.rpg = rpg; measurementChanged(); } }
|
자, 이제 사무국은 값을 변경할 수 있고, arrayList에 옵저버(방송사)들을 추가하거나 제거하여, 자신의 변경사항을 방송국에게 전달해줄 수 있다.
이번엔 방송국 클래스를 만들어보자.
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 50 51 52 53
| package Observer;
public class NBCDisplay implements Observer, DisplayElement{ private float ppg; private float rpg; private float apg; private Subject nbaData;
public NBCDisplay(Subject nbaData){ this.nbaData = nbaData; nbaData.registerObserver(this); }
public void update(float ppg, float rpg, float apg){ this.ppg = ppg; this.apg = apg; this.rpg = rpg; display(); }
public void display() { System.out.printf("This is from NBC!"); System.out.printf(ppg+"points "+rpg+"rebounds "+apg+"assists!!!!\n"); } }
package Observer;
public class TNTDisplay implements Observer, DisplayElement{ private float ppg; private float apg; private float rpg; private Subject nbaData;
public TNTDisplay(Subject nbaData){ this.nbaData = nbaData; nbaData.registerObserver(this); }
@Override public void display() { System.out.printf("This is from TNT!"); System.out.printf(ppg+"points "+rpg+"rebounds "+apg+"assists~!\n"); }
@Override public void update(float ppg, float rpg, float apg) { this.ppg = ppg; this.apg = apg; this.rpg = rpg; display(); } }
|
마지막으로 우리가 만든 녀석들이 잘 작동하는지 확인해보자!
1 2 3 4 5 6 7 8 9 10 11 12 13
| package Observer;
public class NbaBroadcast { public static void main(String[] args) { NBAData nbaData = new NBAData();
TNTDisplay tntDisplay = new TNTDisplay(nbaData); NBCDisplay currentConditionsDisplay = new NBCDisplay(nbaData);
nbaData.setMeasurements(10.2f, 5.23f, 3.3f); nbaData.setMeasurements(20.4f, 12.4f, 7.4f); } }
|
배운 내용 확인하기
1. 서로 상호작용하는 객체들은 느슨하게 연결되어야 한다.
우리는 인터페이스를 통해 옵저버와 서브젝트를 구현했다. 이들은 서로가 어떻게 구현됐는지 관심없다.
그냥 서로가 약속한 인터페이스를 구현하면 된다.