1. 개요
이 사용방법(예제)에서는 Observer 패턴을 설명하고 몇 가지 Java 구현 대안을 살펴보겠습니다.
2. 관찰자 패턴이란 무엇입니까?
관찰자는 행동 디자인 패턴입니다. observable 과 observers 객체 간의 통신을 지정합니다 . Observable 은 관찰자 에게 상태 의 변화 를 알리는 객체입니다 .
예를 들어 뉴스 대행사는 뉴스를 수신할 때 채널에 알릴 수 있습니다. 뉴스 수신은 뉴스 에이전시의 상태를 변경하고 채널에 알림을 발생시킵니다.
직접 구현하는 방법을 살펴보겠습니다.
먼저 NewsAgency 클래스를 정의합니다.
public class NewsAgency {
private String news;
private List<Channel> channels = new ArrayList<>();
public void addObserver(Channel channel) {
this.channels.add(channel);
}
public void removeObserver(Channel channel) {
this.channels.remove(channel);
}
public void setNews(String news) {
this.news = news;
for (Channel channel : this.channels) {
channel.update(this.news);
}
}
}
NewsAgency 는 관찰 가능하며 뉴스 가 업데이트되면 NewsAgency 의 상태가 변경됩니다. 변경 사항이 발생하면 NewsAgency 는 update() 메서드 를 호출하여 관찰자에게 알립니다 .
그렇게 하기 위해서는 관찰 가능한 객체가 관찰자에 대한 참조를 유지해야 합니다. 우리의 경우에는 채널 변수입니다.
이제 채널 클래스인 관찰자가 어떻게 생겼는지 살펴보겠습니다. NewsAgency 의 상태가 변경 될 때 호출되는 update() 메서드 가 있어야 합니다 .
public class NewsChannel implements Channel {
private String news;
@Override
public void update(Object news) {
this.setNews((String) news);
}
// standard getter and setter
}
Channel 인터페이스에는 하나 의 메서드만 있습니다.
public interface Channel {
public void update(Object o);
}
이제 NewsChannel 인스턴스 를 observers List에 추가 하고 NewsAgency 상태를 변경하면 NewsChannel 인스턴스 가 업데이트됩니다.
NewsAgency observable = new NewsAgency();
NewsChannel observer = new NewsChannel();
observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");
Java 코어 라이브러리 에는 미리 정의된 Observer 인터페이스가 있어 관찰자 패턴을 훨씬 더 간단하게 구현할 수 있습니다. 그것을 보자.
3. 옵저버 로 구현
java.util.Observer 인터페이스는 update () 메서드를 정의하므로 이전 섹션에서 했던 것처럼 직접 정의할 필요가 없습니다.
구현에서 어떻게 사용할 수 있는지 봅시다.
public class ONewsChannel implements Observer {
private String news;
@Override
public void update(Observable o, Object news) {
this.setNews((String) news);
}
// standard getter and setter
}
여기에서 두 번째 인수는 아래에서 볼 수 있듯이 Observable 에서 가져옵니다.
observable 을 정의하려면 Java의 Observable 클래스를 확장해야 합니다.
public class ONewsAgency extends Observable {
private String news;
public void setNews(String news) {
this.news = news;
setChanged();
notifyObservers(news);
}
}
관찰자의 update() 메서드를 직접 호출할 필요가 없습니다 . setChanged() 및 notifyObservers() 만 호출 하면 Observable 클래스가 나머지 작업을 수행합니다.
또한 관찰자 List을 포함하고 해당 List, addObserver() 및 deleteObserver()를 유지 관리하는 메서드를 노출합니다.
결과를 테스트하려면 이 List에 관찰자를 추가하고 뉴스를 설정하기만 하면 됩니다.
ONewsAgency observable = new ONewsAgency();
ONewsChannel observer = new ONewsChannel();
observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");
Observer 인터페이스는 완벽하지 않으며 Java 9 이후로 더 이상 사용되지 않습니다. 단점 중 하나는 Observable 이 인터페이스가 아니라 클래스이며 하위 클래스를 observable로 사용할 수 없는 이유입니다.
또한 개발자는 Observable 의 동기화된 메서드 중 일부를 재정의 하고 스레드 안전성을 방해할 수 있습니다.
이제 Observer 보다 권장되는 ProperyChangeListener 인터페이스를 살펴보겠습니다 .
4. PropertyChangeListener 로 구현
이 구현에서 Observable은 PropertyChangeSupport 인스턴스에 대한 참조를 유지해야 합니다. 클래스의 속성이 변경될 때 관찰자에게 알림을 보내는 데 도움이 됩니다.
관찰 가능 항목을 정의해 보겠습니다.
public class PCLNewsAgency {
private String news;
private PropertyChangeSupport support;
public PCLNewsAgency() {
support = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener pcl) {
support.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener(PropertyChangeListener pcl) {
support.removePropertyChangeListener(pcl);
}
public void setNews(String value) {
support.firePropertyChange("news", this.news, value);
this.news = value;
}
}
이 지원 을 사용하여 관찰자를 추가 및 제거하고 관찰 가능 상태가 변경되면 알릴 수 있습니다.
support.firePropertyChange("news", this.news, value);
여기서 첫 번째 인수는 관찰된 속성의 이름입니다. 그에 따라 두 번째 및 세 번째 인수는 이전 값과 새 값입니다.
관찰자는 PropertyChangeListener 를 구현해야 합니다 .
public class PCLNewsChannel implements PropertyChangeListener {
private String news;
public void propertyChange(PropertyChangeEvent evt) {
this.setNews((String) evt.getNewValue());
}
// standard getter and setter
}
우리를 위해 연결해주는 PropertyChangeSupport 클래스 로 인해 이벤트에서 새 속성 값을 복원할 수 있습니다.
구현이 제대로 작동하는지 테스트해 보겠습니다.
PCLNewsAgency observable = new PCLNewsAgency();
PCLNewsChannel observer = new PCLNewsChannel();
observable.addPropertyChangeListener(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");
5. 결론
이 기사에서는 Java에서 Observer 디자인 패턴 을 구현하는 두 가지 방법을 살펴보았습니다 . PropertyChangeListener 접근 방식이 선호 된다는 것을 배웠습니다 .
이 기사 의 소스 코드는 GitHub에서 사용할 수 있습니다 .