2011년 5월 23일 월요일

The Observer Pattern

19. The Observer Pattern
주가 정보의 변화 내역을 그래프와 테이블 또는 그래프와 리스트 박스의 형식으로 표현해야 할 경우가 있다. 주가 정보가 변경될 때마다 수행해야 하는 추가적인 작업 없이 이런 변경 내용을 한 번에 모든 출력물에 반영할 수 있게 되기를 원한다.
*


자바언에서는 Observer 패턴을 이용하여 이런 구현 목적에 맞게 프로그램을 쉽게 개발 할수 있다.
Observer 패턴은 데이터를 포함하는 객체가 데이터의 내용을 출력하는 객체와는 분리되어 있으며, 이러한 데이터 객체들은 데이터 안의 변화를 관찰한다는 전제하에서 사용된다.
그림은 이러한 내용을 도식화한 것이다.
Observer 패턴을 구현할 때는 일반적으로 데이터를 주제로 그리고 각 출력 결과물을 Observer 요소로 언급한다. 각각의 Observer 요소는 데이터에 자신의 관심 사항을 등록하는데, 주제 요소의 public 메소드를 호출함으로써 등록 작업이 이루어지게 된다. 각각 Observer 요소들은 데이터의 내용이 변경될 때 주제 요소가 호출하는 알려진 인터페이스를 갖는다. 이런 인터페이스들은 다은과 같이 정의 할수 있다.
abstract interface Observer {
//변경이 일어났는지를 Observer에게 알린다.
public void sendNotify (String s);
}
abstract interface Subject {
//변경에 관심이 있다는 것을 Subject에게 알린다.
public void registerInterested (Observer obs);
}


이런 abstract 인터페이스를 정의함으로써 얻을 수 있는 장점은 개발자가 원하는 모든 종류의 클래스를 해당 클래스가 이런 인터페이스를 구현하는 한 얼마든지 만들어낼 수 있다는 것이다. 또한 해당 요소들이 어떤 일을 수행하든지 객체들이 주제 요소 및 Observer 요소의 유형을 갖도록 선언할 수 있다는 것이다.

구조

*


역할
  • Subject : subject는 관련된 observers를 알고있다. 관련된 여러 observer objects은 subject를 observe하고 있다. subject는 observer objects을 attaching 과 detaching하는 interface을 제공한다.
  • Observer : observer는 updating interface를 정의하며, subject가 변할 때 update interface는 호출된다.
  • ConcreteSubject : ConcreteSubject는 ConcreteObserver Objects가 필요로 하는 state를 저장하고 있다. ConcreteSubject의 state가 변할 때, ConcreteSubject는 관련된 Observers에게 통보한다.
  • ConcreteObserver : ConcreteObserver는 ConcreteSubject object의 reference를 가지고 있다. ConcreteObserver는 subject의 state와 consistency를 유지한다. ConcreteObserver는 updating interface를 구현하여, subject의 state와 consistency를 유지한다.

의도
하나의 object 상태가 변할 때, 관련된 object들이 자동으로 notified and updated되기 위한 object들간의 one-to-many dependency을 정의한다.

적용시기
  • 어떤 abstraction이 두 개의 사물(aspects)과 하나의 dependent을 가질 때이다. 분리된 objects내의 두 개의 사물(aspects)을 캡슐화 시키는 것은 objects을 독립적이며 다양하게 재사용 할 수 있도록 한다.
  • 하나의 object가 변할 때 다른 objects가 변화하여야 하며, 얼마나 많은 objects가 변화해야 하는지 모를 때이다.
  • 어떤 object가 다른 objects에게 통보할 때, 어떤 기능을 하는지 알 필요가 없을 때이다.

결론
Observer들은 Subject들에게 추상적인 커플링을 조장한다. 어떤 Subject는 Subject의 observer들에 대해 자세히 알지 못한다. 그러나 이것은 데이터를 변경시키는 것이 증가할 때 Observer들을 연속적이거나 반복적으로 업데이트를 해야 하는 단점을 가질 수 있다. 업데이트 비용이 높다면 Observer들이 너무 자주 통보 받지 않도록 변경을 관리하는 어떤 정렬을 도입할 필요가 있다.
Mediator 와 Observer
Mediator와 Observer 패턴은 둘다 ‘상태 변화를 통진한다.’ 는 점은 닮아 있지만 목적이나 시점이 다르다.
Mediator 패턴은 상태 변화가 통지되긴 하지만 그것은 colleague 역할을 조정하기 위한 목적으로 작동하고 있는 mediator의 일부에 지나지 않는다.
Observer 패턴에서는 subject 역할의 상태 변화를 Observer 역할에게 통지하는 것, 통지를 해서 동기를 받아들이는 것이 핵심이다.

Observer 인터페이스와 Observable 클래스
자바 언어는 다음과 같은 메소드를 갖는 java.util.observer인터페이스를 갖는다.
public void update(Observable o, Object arg)
위의 메소드는 관찰 대상인 객체의 내용이 변경될 때마다 호출되도록 만들어진 메소드이다. 이것은 두 번째 아규먼트가 해당 변경 사항의 성격을 기술하기 위해 사용될수 있다.
그러나 불행하게도 관찰 가능하다는 특성은 대부분 인터페이스보다는 클래스에서 구현된다. 따라서 개발자는 해당 속성을 기본 클래스의 성격이 아직 규정되지 않았을 경우에만 사용할 수 있다. 그러나 이런 경우는 GUI 어플리케이션에서는 거의 일어나지 않기 때문에 Observable 클래스는 거의 사용되지 않는다. 반면 개발자는 이런 Observer 인터페이스를 쉽게 이용할 수 있다.


예제소스



예제 소스
public interface Observer {
public abstract void update(NumberGenerator generator);
}
public class DigitObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.println("DigitObserver:" + generator.getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
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) {
}
}
}
import java.util.Vector;
import java.util.Iterator;
public abstract class NumberGenerator {
private Vector observers = new Vector();
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();
}
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();
}
}
}
public class mainClass {
public static void main(String[] args) {
mainClass client = new mainClass();
client.exec();
}
public void exec() {
NumberGenerator generator = new RandomNumberGenerator();
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}


관련패턴
  • Mediator pattern : Mediator 패턴에서는 Mediator와 Colleague 역할이 통신할 때 Observer 패턴을 사용하는 경우가 있다.

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...