개요
Observer(관찰자) 패턴은 관찰 대상의 상태 변화를 알려주기 위한 패턴으로 어떤 대상의 상태변화에 따른 작업을 처리할 때 적합한 패턴이다.
역할
Subject 역할
관찰 대상으로 Observer 역할을 자신에게 등록하고 삭제하는 메소드를 갖는다. 그리고 현재 상태를 취득하는 메서드를 선언한다. 예제에서는 NumberGenerator 클래스.
ConcreteSubject 역할
구체적인 관찰 대상으로 상태가 변할 때 자신에게 등록해놓은 Observer 역할에게 이를 전달한다. 예제에서는 RandomNumberGenerator 클래스.
Observer 역할
Subject가 상태가 변할 때 이를 전달받는 역할로 이를 위한 인터페이스를 선언한다. 예제에서는 Observer 클래스가 이 역할이며 상태 변화를 전달 받는 메서드는 update 메서드이다.
ConcreteObserver 역할
Observer를 구체화 하는 역할로 update 메소드가 호출될 때 Subject 역할의 상태에 대한 정보를 얻는다. 예제에서는 DigitObserver, GraphObserver 클래스.
이득 및 주의사항
Subject는 자신이 어떤 ConcreteObserver 인스턴스를 가지고 있는지 몰라도 상관없다. 그저 자기가 저장하고 있는 Observer 인스턴들을 가지고 update 메서드를 호출하기만 하면 된다.
반대로 Observer는 자신이 관찰하고 있는 Subject가 어떤 ConcreteSubject 인스턴스인지 신경쓰지 않아도 된다.
결과적으로 이전에 학습한 디자인 패턴과 같이 실제 구체화된 인스턴스가 무엇인지 상관없이 모두 동일한 인터페이스를 가지고 있기에 구체화 하는 클래스를 필요에 따라 쉽게 교체할 수 있다.
Subject 인스턴스가 가지고 있는 Observer 인스턴스들은 저장된 순서가 정해져 있다. 만약 Observer 인스턴스간의 상호 의존성이 있어 호출 순서가 지켜져야 한다면 순서에 따른 오류가 발생하지 않도록 주의해야한다. 그리고 그보다는 각 인스턴스간 독립성을 보장하도록 하는 것이 더 바람직한다.
Observer가 Subject의 상태 변화에 따라 어떤 동작을 할때 Subject 인스턴스를 가지고 동작해야 한다면 무한루프에 빠지지 않도록 주의해야 한다. 다시 말하자면 Subject의 상태 변화로 인해 Observer가 동작하고 이로인해 다시 Subject의 상태가 변하면서 Observer가 동작하는 끝없는 반복 상태를 말한다.
예제 코드
//Subject 역할
package observer;
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();
}
//ConcreteSubject역할
package observer;
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();
}
}
}
//Observer 역할
package observer;
public interface Observer {
public abstract void update(NumberGenerator generator);
}
//ConcreteObserver 역할1
package observer;
public class DigitObserver implements Observer{
public void update(NumberGenerator generator) {
System.out.println("DigitObserver : " + generator.getNumber());
try {
Thread.sleep(100);
} catch(InterruptedException e) {
}
}
}
//ConcreteObserver 역할2
package observer;
public class GraphObserver implements Observer{
public void update(NumberGenerator generator) {
System.out.println("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) {
}
}
}
//Tester
package observer;
public class ObserverTester {
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();
}
}
'디자인 패턴' 카테고리의 다른 글
20. Flyweight 패턴 (0) | 2021.01.05 |
---|---|
18. Memento 패턴 (0) | 2020.12.30 |
16. Mediator 패턴 (0) | 2020.12.28 |
15. Facade 패턴 (0) | 2020.12.26 |
14. Chain of Responsibility 패턴 (0) | 2020.12.22 |