1. 개념
1) 한 객체 상태가 바뀌면 해당 객체에 의존하는
다른 객체들에게도 연락이 가고 자동으로 내용이
갱신되는 방식으로 1:n 의존성을 정의
서로 영향을 미치는 객체를 간접적으로 연결
2)
Subject, Observer를 interface로 정의하고
각각 구현체가 implements 한다.
Observer구현체가 Subject 구현체에서 정의한 옵저버 등록,
삭제가 가능하고
Observer 등록시 Subject 내용 변경시 변경된 내용이
Observer 구현체로 전달된다.
이렇게 서로 양 쪽 구현체가 서로에게 영향을 미쳐야 되는 경우
interface를 통한 결합시 서로 독립적으로 움직 일 수 있다.
(ConcreateObserver 중 하나는 추가,
삭제하더라도 이상없이 동작)
자바에서는 Observer 를 상속받아 여러 이벤트리스너를
구현해놨다.
2. 구현
1) 프로젝트 구성
2) 코드
(1) 사용 클래스1 CurrentConditionsDisplay.java
package weather;
package callEtc;
import observerA.Observer;
import subjectA.Subject;
import displayA.DisplayElement;
public class CurrentConditionsDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("Current conditions: " + temperature
+ ", F degrees and " + humidity + "% humidity");
}
@Override
public void update(float temperature, float humidity, float pressure) {
// TODO Auto-generated method stub
this.temperature = temperature;
this.humidity = humidity;
display();
}
}
(2) 사용클래스2- ForecastDisplay
package weather;
package callEtc;
import observerA.Observer;
import subjectA.Subject;
import displayA.DisplayElement;
public class ForecastDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
// private float pressure;
private Subject weatherData;
public ForecastDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
// weatherData.removeObserver(this);
}
@Override
public void display() {
// TODO Auto-generated method stub
float max;
float min;
float avg;
if(temperature< humidity){
max= humidity;
min=temperature;
}else{
max= temperature;
min=humidity;
}
avg = (max+min)/2;
System.out.println("Avg/Max/Min temperature = " + avg
+ "/" + max + "/"+min);
}
@Override
public void update(float temperature, float humidity, float pressure) {
// TODO Auto-generated method stub
this.temperature = temperature;
this.humidity = humidity;
//this.pressure = pressure;
display();
}
}
(3) interface DisplayElement
package weather;
package displayA;
public interface DisplayElement {
public void display();
}
(4) interface Observer
package weather;
package observerA;
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
(5) interface Subject
package weather;
package subjectA;
import observerA.Observer;
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
(6) WeatherData
package weather;
package subjectA;
import java.util.ArrayList;
import observerA.Observer;
public class WeatherData implements Subject{
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observers = new ArrayList();
}
@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
int i = observers.indexOf(o);
if(i>=0){
observers.remove(i);
}
}
@Override
public void notifyObservers() {
// TODO Auto-generated method stub
for(int i=0; i< observers.size();i++){
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setmeaurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity=humidity;
this.pressure = pressure;
measurementsChanged();
}
}
(7) TEST 확인용 클래스
package weather;
import subjectA.WeatherData;
import callEtc.CurrentConditionsDisplay;
import callEtc.ForecastDisplay;
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setmeaurements(80, 70, 30.4f);
weatherData.setmeaurements(60, 50, 20.4f);
}
}
3) 테스트
Current conditions: 80.0, F degrees and 70.0% humidity
Avg/Max/Min temperature = 75.0/80.0/70.0
Current conditions: 60.0, F degrees and 50.0% humidity
Avg/Max/Min temperature = 55.0/60.0/50.0
ps2. Java Design pattern 예제
Observer
public interface Observer {
public abstract void update(NumberGenerator generator);
}
NumberGenerator
import java.util.Vector;
import java.util.Iterator;
public abstract class NumberGenerator {
private Vector observers = new Vector(); // Observer들을 보관
public void addObserver(Observer observer) { // Observer를 추가
observers.add(observer);
}
public void deleteObserver(Observer observer) { // Observer를 삭제
observers.remove(observer);
}
public void notifyObservers() { // Observer에 통지
Iterator it = observers.iterator();
while (it.hasNext()) {
Observer o = (Observer)it.next();
o.update(this);
}
}
public abstract int getNumber(); // 수를 취득한다.
public abstract void execute(); // 수를 생성한다.
}
RandonNumberGenerator -- number Generator와 동일
import java.util.Random;
public class RandomNumberGenerator extends NumberGenerator {
private Random random = new Random(); // 난수발생기
private int number; // 현재의 수
public int getNumber() { // 수를 취득한다.
return number;
}
public void execute() {
for (int i = 0; i < 20; i++) {
number = random.nextInt(50);
notifyObservers();
}
}
}
----- Oberser 구현체
public class DigitObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.println("DigitObserver:" + generator.getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
-------- 옵저버 구현체2 GraphjObserver
public class GraphObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.print("GraphObserver:");
int count = generator.getNumber();
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println("");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
---- 테스트 클래스
public class Main {
public static void main(String[] args) {
NumberGenerator generator = new RandomNumberGenerator();
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}
결과 :
DigitObserver:21
GraphObserver:*********************
DigitObserver:40
GraphObserver:****************************************
DigitObserver:7
GraphObserver:*******
DigitObserver:5
GraphObserver:*****
DigitObserver:39
GraphObserver:***************************************
DigitObserver:48
GraphObserver:************************************************
DigitObserver:38
GraphObserver:**************************************
DigitObserver:43
GraphObserver:*******************************************
DigitObserver:35
GraphObserver:***********************************
DigitObserver:32
GraphObserver:********************************
DigitObserver:8
GraphObserver:********
DigitObserver:25
GraphObserver:*************************
DigitObserver:15
GraphObserver:***************
DigitObserver:36
GraphObserver:************************************
DigitObserver:40
GraphObserver:****************************************
DigitObserver:23
GraphObserver:***********************
DigitObserver:0
GraphObserver:
DigitObserver:19
GraphObserver:*******************
DigitObserver:12
GraphObserver:************
DigitObserver:44
GraphObserver:********************************************
3. 기타
(1) 위키
https://ko.wikipedia.org/wiki/%EC%98%B5%EC%84%9C%EB%B2%84_%ED%8C%A8%ED%84%B4
(2) Powerful Programing 옵저버 패턴
저보다 더 잘정리되어 있습니다.
내용도 같고 예제도 같음
http://warmz.tistory.com/751
4. 관련패턴
1) Mediator 패턴