Observer 패턴
객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다.
+ 발행/구독 모델이라고도 칭한다.
신기한 점 1. 사실 관찰하는 것이 아니라, 상태변화를 '통지받는다'.
신기한 점 2. 교환 가능성이 있다.
RandomNumberGenerator 클래스는,
현재 자신을 관찰하고 있는 것이 DigitObserver의 인스턴스인지 GraphObserver의 인스턴스인지 모른다.
다만, 이들이 Observer 인터페이스를 구현하고 있다는 것만 안다.
한편, DigitObserver 클래스는,
자신이 관찰하고 있는 것이 RandomNumberGenerator의 인스턴 스인지 다른 XXXXXNumberGenerator의 인스턴스인지 신경쓰지 않는다.
다만, 관찰대상이 NumberGenerator의 하위 클래스의 인스턴스 이고 getNumber 메소드를 가지고 있다는 것만 알고 있다.
–> 관찰자와 관찰 대상을 논리적으로 분리함으로써, 각각을 쉽게 교체할 수 있다
=> 확장성/교환 가능성이 높아진다.
신기한 점 3. Observer 인터페이스가 이미 구현되어있지만, 다중상속을 지원하지 않는 자바의 특성때문에 잘 사용되지 않는다. 직접 인터페이스를 짜 확장하는 것이 일반적이라고 한다.
연습문제
17-1) NumberGenerator 클래스를 확장하고, 수가 점점 증가하는 기능이 있는 Incremental NumberGenerator라는 하위 클래스를 작성하십시오.
생성자의 인수로써 [개시하는 수, 종료하는 수 (포함x), 증가분] 이라는 3개의 Int를 전달한다고 가정합니다.
그리고 DigitObserver 클래스와 GraphObserver 클래스에 동작을 관찰시키는 프로그램을 작성하십시오.
Incremental NumberGenerator를 사용한 Main 클래스
public class Main {
public static void main(String[] args) {
NumberGenerator generator = new IncrementalNumberGenerator(10, 50, 5);
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}
(예를 들어 개시하는 수 = 10, 종료하는 수(포함x) = 50, 증가분 = 5 라면,
10, 15, 20, 25, ... 40, 45 의 숫자와 그래프가 출력된다. )
답)
Incremental NumberGenerator 클래스
public class IncrementalNumberGenerator extends NumberGenerator {
private int number; // 개시하는 수
private int end; // 종료하는 수 (포함하지 않는다)
private int inc; // 증가분
public IncrementalNumberGenerator(int start, int end, int inc) {
this.number = start;
this.end = end;
this.inc = inc;
}
public int getNumber() { // 수를 취득한다.
return number;
}
public void execute() {
while (number < end) {
notifyObservers();
number += inc;
}
}
}
17-2) 예제 프로그램에 추가하는 형태로 새로운 ConcreteObserver 역할을 작성하십시오. Main 클래스를 변경해서 그 ConcreteObserver 역할을 이용하도록 하십시오.
GUI를 사용하는 원 모양의 FrameObserver를 생성하였다.
FrameObserver에서는 GraphText와 GraphCanvas를 호출하고 있다.
FrameObserver 클래스
public class FrameObserver extends Frame implements Observer, ActionListener {
private GraphText textGraph = new GraphText(60);
private GraphCanvas canvasGraph = new GraphCanvas();
private Button buttonClose = new Button("Close");
public FrameObserver() {
super("FrameObserver");
setLayout(new BorderLayout());
setBackground(Color.lightGray);
textGraph.setEditable(false);
canvasGraph.setSize(500, 500);
add(textGraph, BorderLayout.NORTH);
add(canvasGraph, BorderLayout.CENTER);
add(buttonClose, BorderLayout.SOUTH);
buttonClose.addActionListener(this);
pack();
show();
}
public void actionPerformed(ActionEvent e) {
System.out.println(e.toString());
System.exit(0);
}
public void update(NumberGenerator generator) {
textGraph.update(generator);
canvasGraph.update(generator);
}
}
class GraphText extends TextField implements Observer {
public GraphText(int columns) {
super(columns);
}
public void update(NumberGenerator generator) {
int number = generator.getNumber();
String text = number + ":";
for (int i = 0; i < number; i++) {
text += '*';
}
setText(text);
}
}
class GraphCanvas extends Canvas implements Observer {
private int number;
public void update(NumberGenerator generator) {
number = generator.getNumber();
repaint();
}
public void paint(Graphics g) {
int width = getWidth();
int height = getHeight();
g.setColor(Color.white);
g.fillArc(0, 0, width, height, 0, 360);
g.setColor(Color.red);
g.fillArc(0, 0, width, height, 90, - number * 360 / 50);
}
}
참고한 블로그가 예시가 넘 웃겨서 첨부
https://pjh3749.tistory.com/266
[디자인패턴] 옵저버 패턴 (Observer Pattern) 아주 간단하게 정리해보기
옵저버 패턴이란? 옵저버란 스타크래프트 프로토스의 유닛으로 적들을 관찰하기 위해 탄생한 유닛이다. 테란전에서 필수 유닛이며 옵저버 패턴(observer pattern)은 객체의 상태 변화를 관찰하는 관
pjh3749.tistory.com
'JAVA' 카테고리의 다른 글
[디자인패턴] Proxy 패턴 (0) | 2022.06.02 |
---|---|
[디자인패턴] State 패턴 (0) | 2022.05.25 |
[디자인패턴] façade 패턴 (0) | 2022.05.12 |
[디자인패턴] Decorator 패턴 (0) | 2022.04.28 |
[디자인패턴] Composite 패턴 (0) | 2022.04.12 |