Observer Pattern

개념
- 관찰대상의 상태가 변하면 관찰자에게 통지되는 패턴.상태 변화에 따른 처리를 기술할때 유효함, 엑셀 스트레드쉬트

I. 의도

     일대다의 관련성을 갖는 객체들의 경우 한 객체의 상태가 변하면 다른 모든 객체에게 그 사항을 알리고 필요한 경우 자동적으로 수정이 이루어지도록 한다  
        정의: 관찰대상의 상태가 변하면 관찰자에게 통지되는 패턴.상태 변화에 따른 처리를 기술할때 유효함, 엑셀 스트레드쉬트
              : 자바에서 지원하는 java.util.Observer가 있으며 푸시(subject가 보내는),풀 방식(옵저버에서 Observale객체로부터 원하는 데이터를 가져 오는 방식)이 있다

II. 활용

  • 추상화 개념이 2가지 측면이 있고 하나가 다른 하난에 종속적일 때 이런 종속관계를 하나의 객체로 분리시켜 이들 각각을 재활용 할 수 있다
  • 다른 객체에 변화를 통보할 때, 변화에 관심있어 하는 객체들이 누구인가에 대한 가정없이 이루어져야할 때

III. 결과

  • 대상과 관찰자 모두를 독립적으로 변형하기 쉽다
  • subject와 observer 클래스 간에는 추상화된 결합도만 존재한다.
  • Broadcast 방식의 교류를 가능하게 한다
  • 예측하지 못한 수정이 발생할 수 있다 – 관찰자가 무엇이 변했는지를 알수 있게 하는 추가적인 프로토콜없이는 변경 유추가 매우 어렵다

관련 패턴: 복잡한 수정 방법을 캡슐화한다는 점에서 changeManager 클래스는 대상과 관찰자 간의 Mediator 클래스이기도 한다.  ChangeManager는 시스템에 하나만 존재하면 되므로 Singleton이다

3. Observer패턴의 동작절차

1) Observer의 구현클래스(concrete Observer A, Concrete Observer B)에서 Subject의 Register Observer()를 이용해 Subject에 등록

2) Subject의 상태가 변경되면 notify Observer()를 호출하고, notify Observer()에서는 등록된 모든 Observer들의 notify()를 호출함. 이때 매개변수로 값을 넘길수도 있음.

3)만약 subject를 멤버로 가지고 있으면, remove observer를 통해 subject에서 observer를 해제할 수 있음

 

Subject: 관찰자들을 알고 있다. 다수의 Observer 객체는 대상을 관찰한다. Observer 객체를 대상과 연결하거나 무관한 것으로 만드는 데 필요한 인터페이스를 갖는다.

  • Observer: 대상에 생긴 변화에 관심 있는 객체를 변경하는데 필요한 인터페이스를 갖고 있다. 이로써 Subject 의 변경에 따라 변화되어야 하는 객체들의 일관성을 유지한다.
  • ConcreteObserver: ConcreteSubject 객체에 대한 참조자를 관리한다. 대상과 일관성을 유짛해야 하는 상태를 저장하고 있다. 대상과 일관성을 유지하기 위해 관찰자를 수정해야 하므로 이에 필요한 인터페이스를 구현한다.

 

Observer.java
//옵저버를 나타내는 인터페이스
public interface Observer {
 public abstract void update(NumberGenerator generator);
}

 

NumberGenerator.java
import java.util.ArrayList;
import java.util.Iterator;

//수를 생성하는 오브젝트를 나타내는 추상 클래스
//실제 수의 생성 과 수의 취득은 하위클래스에서 구현
public abstract class NumberGenerator {
//옵저버에 리스트 생성
private ArrayList observers = new ArrayList();

//옵저버 추가
public void addObserver(Observer observer){
 observers.add(observer);
}

//옵저버 삭제
public void deleteObserver (Observer observer){
 observers.remove(observer);
}

//옵저버에 알림
public void notifyObservers(){
Iterator it = observers.iterator();
while(it.hasNext()){
 Observer o = (Observer)it.next();
 o.update(this);
}
}

//수를 취득하는 메소드
public abstract int getNumber();
//수를 생성하는 메소드
public abstract void execute();
}
 

RandomNumberGenerator.java
import java.util.Random;
// 랜덤으로 수를 생성하는 클래스
// NumberGenerator 클래스의 하위 클래스
public class RandomNumberGenerator extends NumberGenerator{
//난수발생기 생성
Random random = new Random();

//현재의 숫자
int number;

//수를 취득하는 메소드
public int getNumber(){
 return number;
}

//수를 생성하는 메소드
public void execute(){
 //20번 반복
 for(int i=0; i<20; i++){
 //0~50 까지의 난수 생성 후 옵저버에게 알림
  number = random.nextInt(50);
  notifyObservers();
 }
}
}
DigitObserver.java
//숫자를 수로 표시하는 클래스
public class DigitObserver implements Observer{
 public void update(NumberGenerator generator){
  System.out.println("DigitBoserver: " + generator.getNumber());
  try{
   Thread.sleep(100);
  }catch(InterruptedException e){}
 }
}
GraphObserver.java
//숫자를 그래프로 표시하는 클래스
public class GraphObserver implements Observer{
public void update(NumberGenerator generator){
 System.out.print("GraphObserver : ");

 for(int i=0; i<generator.getNumber(); i++){
  System.out.print("*");
 }
 System.out.println();

try{
Thread.sleep(100);
}catch(InterruptedException e){}
}
}
TestObserverPattern.java
//동작확인용 클래스
public class TestObserverPattern {

public static void main(String[] args) {
 NumberGenerator generator = new RandomNumberGenerator();
 generator.addObserver(new DigitObserver());
 generator.addObserver(new GraphObserver());

 generator.execute();
 }
}

 

 

 

댓글