반응형

옵저버 패턴(Observer Pattern)

 

한객체의 상태가바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의한다. 

 

즉, A 오브젝트가 B 오브젝트 상태에 관심이 있어서 B 오브젝트 상태가 변할때 마다 A 오브젝트가 파악할 수 있게 해주는 패턴이다.

 

신문 구독이 대표적인 예이다.(신문 발행자, 구독자 관계)

 

옵저버 패턴의 특징은 Loose Coupling을 잘 만족하여 서로 아는 지식은 적지만, 커뮤니케이션은 가능하다는 점이다.

 

즉, 사용되는 디자인 원칙은 다음과 같다.

 

서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.

 

 

 

 

옵저버 패턴 클래스 다이어그램

 

 

 

옵저버 패턴 예제

 

Observer 인터페이스 정의

인터페이스 내에 update 메서드를 정의한다.

package ObserverPattern;

public interface Observer {
	public void update(String title, String news);
}

 

 

 

Publisher 인터페이스 정의

인터페이스 내에 아래 3가지 메서드를 정의하여 publisher이 행동 할 수 있는 것들을 명시한다.

package ObserverPattern;

public interface Publisher {
	public void registerObserver(Observer observer);
	public void removeObserver(Observer observer);
	public void notifyObservers();
}

 

 

 

 

NewsPublisher 클래스 구현

Publisher 인터페이스를 직접 이용하는 클래스

 

observers를 ArrayList에 모을 수 있게 한다.

그 외에는 아래 코드를 참고한다.

package ObserverPattern;

import java.util.ArrayList;

public class NewsPublisher implements Publisher{
	private ArrayList<Observer> observers;
	private String title;
	private String news;
	
	public NewsPublisher() {
		observers = new ArrayList<>();
		title = null;
		news = null;
	}
	
	@Override
	public void registerObserver(Observer observer) {
		observers.add(observer);
	}
	@Override
	public void removeObserver(Observer observer) {
		int index = observers.indexOf(observer);
		observers.remove(index);
	}
	@Override
	public void notifyObservers() {
		for(Observer observer : observers) {
			observer.update(title, news);
		}
	}
	
	public void setNews(String title, String news) {
		this.title = title;
		this.news = news;
		notifyObservers();
	}
}

 

 

 

NewsSubscriber 클래스 구현

Observer 인터페이스를 직접 이용하는 클래스 

 

NewsSubscriber이 생성될 때 자신의 publisher이 누구인지 지정해준다.

그때 자신의 publisher의 registerObserver에 의해 등록이 될 것이고

추후 publisher의 notifyObservers()에서 publisher의 모든 observer가 내용을 전달받게 된다.

package ObserverPattern;

public class NewsSubscriber implements Observer{
	private String observerName;
	private String news;
	private Publisher publisher;
	
	public NewsSubscriber(String subscriber, Publisher publisher) {
		this.observerName = subscriber;
		this.publisher = publisher;
		publisher.registerObserver(this);
	}
	
	@Override
	public void update(String title, String news) {
		this.news = title + "!!! " + news;
		display();
	}
	
	private void display() {
		System.out.println("=== " + observerName + " 수신 내용 ===\n" + news + "\n");
	}
}

 

 

 

ObserverPatternMain 클래스 구현

package ObserverPattern;

public class ObserverPatternMain {

	public static void main(String[] args) {
		NewsPublisher newsPublisher = new NewsPublisher();

		NewsSubscriber newsSubscriber1 = new NewsSubscriber("옵저버1", newsPublisher);
		NewsSubscriber newsSubscriber2 = new NewsSubscriber("옵저버2", newsPublisher);

		newsPublisher.setNews("특보", "옵저버 패턴이 만들어졌습니다.");
		newsPublisher.setNews("정정", "옵저버 패턴으로 내용이 정정됨을 알립니다.");
		
		newsPublisher.removeObserver(newsSubscriber1);
		newsPublisher.setNews("속보", "누군가 구독 해제를 했습니다.");
	}

}

 

 

 

=== 옵저버1 수신 내용 === 
특보!!! 옵저버 패턴이 만들어졌습니다. 

=== 옵저버2 수신 내용 === 
특보!!! 옵저버 패턴이 만들어졌습니다. 

=== 옵저버1 수신 내용 === 
정정!!! 옵저버 패턴으로 내용이 정정됨을 알립니다. 

=== 옵저버2 수신 내용 === 
정정!!! 옵저버 패턴으로 내용이 정정됨을 알립니다. 

=== 옵저버2 수신 내용 === 
속보!!! 누군가 구독 해제를 했습니다.

 

 

정리

 

옵저버 패턴은 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 연락이 가고 자동으로 정보가 갱신되는 1:N 의 관계를 정의한다.


옵저버 패턴은 주제와 옵저버가 느슨하게 결합되어있는 객체 디자인을 제공한다.

 

주제가 옵저버에 대해서 아는 것은 옵저버가 특정 인터페이스(Observer 인터페이스)를 구현 한다는 것 뿐. 
옵저버는 언제든지 새로 추가할 수 있음. (주제는 Observer인터페이스 구현하는 객체 목록에만 의존하기때문)


주제나 옵저버가 바뀌더라도 서로에게 전혀 영향을 주지않는다. 

그래서 주제와 옵저버는 서로 독립적으로 재 사용할수 있다. 

느슨하게 결합하는 디자인을 사용하면 변경 사항이 생겨도 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할수 있다. (객체 사이의 상호 의존성을 최소화 할 수 있기 때문) 

새로운 형식의 옵저버를 추가하려해도 주제를 전혀 변경할 필요가 없음. (새로운 클래스에서 Observer 인터페이스만 구현해주면됨) 

옵저버 패턴은 푸시 방식과 풀 방식으로 언제든지 구현할 수 있다.


JAVA에서 기본으로 Observable 클래스와 Observer 인터페이스를 제공한다.


Swing, Android 등에서 UI관련된 곳에서 이 옵저버 패턴이 많이 사용된다.



반응형