2015년 6월 24일 수요일

클래스 디자인 패턴 2. Observer Pattern_


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 패턴



댓글 없음:

댓글 쓰기