1. - 1 -
Observer Design Pattern in Java
원본 주소 : http://www.vogella.com/articles/DesignPatternObserver/article.html
번역자 : 김형석 수석
번역일 : 2013 년 05 년 15 일
이 글은 Java 언어로 프로그래밍하는 데 있어 관찰자 디자인 패턴이 무엇이고 어떻게
사용하는지에 대해 다룹니다.
1. 관찰자 패턴 (Observer Pattern)
1) 정의
관찰자 패턴은 여러 객체 간의 일대다(one-to-many) 의존관계를 정의하는 디자인 패턴으로,
한 객체의 상태가 변경되었을 때 그 객체에 의존하고 있는 나머지 객체들이 변경 사항을
통보받고 자동적으로 어떤 동작을 수행하도록 하기 위해 사용됩니다.
여기서 관찰의 대상이 되는 객체를 대상(subject)이라 하고, 대상의 상태 변화를 주시하고
있는 객체를 관찰자(observer) 혹은 리스너(listener)라고 합니다.
2) 사용 예
관찰자 패턴은 Java 에서 흔히 사용되고 있습니다. 예를 들어 사용자 인터페이스(UI)에서
사용되는 버튼(button)을 위해 리스너(listener)를 정의하는 것이 관찰자 패턴의 입니다.
버튼이 선택되면 리스너가 해당 내용을 통지받아 특정 동작을 수행하게 됩니다.
하지만 관찰자 패턴이 하나의 사용자 인터페이스 컴퍼넌트에서만 사용될 수 있는 것은
아닙니다.
예를 들어 어플리케이션 내에 현재 온도를 표시해주는 partA 라고 하는 부분이 있다고
가정해봅시다. 그리고 partB 는 현재 온도가 20 도가 넘으면 녹색 불빛을 표시하기로 했다고
하면, partA 의 상태 변화를 감지하기 위해 partB 는 partA 에 자기 자신을 리스너로
등록해야 할 것입니다.
partA 에서 기온이 변경되면 이벤트가 발생(trigger)될 것입니다. 그리고 이 이벤트는
등록되어 있는 모든 리스너들에게 전달될 것인데, 위의 경우에서는 partB 가 전달을 받습니다.
이제 partB 는 이벤트와 같이 전달된 정보를 얻어 화면을 갱신할 것입니다.
2. - 2 -
다음은 버튼에 리스너를 설정하는 예제 코드입니다.
Button button = new Button(shell, SWT.PUSH);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// Handle the selection event
System.out.println("Called!");
}
});
3) 예제 코드
다음 예제는 Person 객체 내의 List 정보의 변경을 확인하는 관찰자를 만들 것입니다. 이를
위해 com.vogella.java.designpattern.observer.MyObserver 클래스와 그 외의 몇 가지의
클래스들을 이용할 것입니다.
package com.vogella.java.designpattern.observer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
public class MyModel {
private List<Person> persons = new ArrayList<Person>();
private List<PropertyChangeListener> listeners =
new ArrayList<PropertyChangeListener>();
public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
notifyListeners(this, "firstName",
firstName,
this.firstName = firstName);
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
notifyListeners(this, "lastName",
lastName,
this.lastName = lastName);
}
}
public List<Person> getPersons() {
3. - 3 -
return persons;
}
public MyModel() {
// Just for testing we hard-code the persons here:
persons.add(new Person("Lars", "Vogel"));
persons.add(new Person("Jim", "Knopf"));
}
private void notifyListeners(Object object,
String property, String oldValue, String newValue) {
for (PropertyChangeListener listener : listeners) {
listener.propertyChange(new PropertyChangeEvent(this,
property,
oldValue,
newValue));
}
}
public void addChangeListener(PropertyChangeListener newListener) {
listeners.add(newListener);
}
}
package com.vogella.java.designpattern.observer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class MyObserver implements PropertyChangeListener {
public MyObserver(MyModel model) {
model.addChangeListener(this);
}
@Override
public void propertyChange(PropertyChangeEvent event) {
System.out.println("Changed property: " + event.getPropertyName() + " old:"
+ event.getOldValue() + " new: " + event.getNewValue());
}
}
package com.vogella.java.designpattern.observer;
import com.vogella.java.designpattern.observer.MyModel.Person;
public class Main {
public static void main(String[] args) {
MyModel model = new MyModel();
MyObserver observer = new MyObserver(model);
// We change the last name of the person, observer will get notified
for (Person person : model.getPersons()) {
person.setLastName(person.getLastName() + "1");
}
// We change the name of the person, observer will get notified
for (Person person : model.getPersons()) {
person.setFirstName(person.getFirstName() + "1");
}
}
}
4) 평가
4. - 4 -
관찰자 패턴은 객체 지향 프로그래밍의 원칙 중 하나인 OCP(Open Closed Principle)을
가능케 합니다. 이 원칙은, 클래스들은 확장에는 열려(Open)있어야 하나 변경에는
닫혀(Closed) 있어야 함을 의미합니다.
관찰자 패턴을 이용하면, 대상(subject)은 관찰자를 숫자에 제한 없이 등록할 수 있게 됩니다.
새로운 리스너가 대상 객체를 관찰하려 한다 하더라도 대상 클래스의 코드에는 아무런
변경도 필요하지 않습니다.
즉, 관찰자 패턴은 대상 클래스를 관찰자 클래스로부터 분리(decouple)하도록 해 줍니다.
관찰자만이 대상 클래스의 존재를 인식할 뿐입니다.