[디자인 패턴] Observer 패턴

이멀젼씨

·

2020. 3. 22. 11:22

- 정의

 

어떤 객체에 이벤트가 발생했을 때, 이 객체에 등록된 옵저버들에게 통지하도록 하는 디자인 패턴이다

 

- UML

1. Subject인터페이스는 옵저버들을 추가, 삭제 및 알림 기능을 갖고 있으며 옵저버의 관리 역할을 한다

2. NewspaperPublisher클래스는 Subject인터페이스를 상속받아 옵저버들을 관리할 수 있다

3. Observer인터페이스는 update메소드를 통해 상태가 바뀔때 마다 그에 맞는 행동을 취할 수 있게 만든다

4. Subscriber1, Subscriber2, Subscriber3클래스는 Observer인터페이스를 상속받아 update메소드를 구현한다. 생성자를 통해 NewspaperPublisher에게 자기 자신을 등록하고, unsubscribe메소드를 통해 publisher에 삽입된 자기 자신을 삭제한다

 

- 코드

 

Subject interface

public interface Subject {
	public void add(Observer observer, String s);
	public void delete(Observer observer, String s);
	public void notifyObservers();
}

NewspaperPublisher class

import java.util.ArrayList;

public class NewspaperPublisher implements Subject {

	private ArrayList<Observer> observers;
	
	public NewspaperPublisher() {
		observers = new ArrayList<Observer>();
	}
	
	public void publish() {
		System.out.println("신문을 발행하였습니다.");
		notifyObservers();
	}
	
	@Override
	public void add(Observer observer, String s) {
		System.out.println(s+"이 신문을 구독했습니다.");
		observers.add(observer);
	}
	
	@Override
	public void delete(Observer observer, String s) {
		System.out.println(s+"이 구독을 해지했습니다.");
		observers.remove(observer);
	}
	
	@Override
	public void notifyObservers() {
		for(Observer observer : observers)
			observer.update();
		
	}
}

Observer interface

public interface Observer {
	public void update();
}

Subscriber1 class

public class Subscriber1 implements Observer{
	
	private Subject publisher;
	
	public Subscriber1(Subject publisher) {
		this.publisher = publisher;
		publisher.add(this, "구독자1");
	}
	
	@Override
	public void update() {
		System.out.println("새로운 신문이 구독자 1에게 도착했습니다.");
	}
	
	public void unsubscribe() {
		publisher.delete(this, "구독자1");
	}
}

Subscriber2 class

public class Subscriber2 implements Observer{
	
	private Subject publisher;
	
	public Subscriber2(Subject publisher) {
		this.publisher = publisher;
		publisher.add(this, "구독자2");
	}
	
	@Override
	public void update() {
		System.out.println("새로운 신문이 구독자 2에게 도착했습니다.");
	}
	
	public void unsubscribe() {
		publisher.delete(this, "구독자2");
	}
}

Subscriber3 class

public class Subscriber3 implements Observer {
	
	private Subject publisher;
	
	public Subscriber3(Subject publisher) {
		this.publisher = publisher;
		publisher.add(this, "구독자3");
	}
	
	@Override
	public void update() {
		System.out.println("새로운 신문이 구독자 3에게 도착했습니다.");
	}
	
	public void unsubscribe() {
		publisher.delete(this, "구독자3");
	}
}

Main class

public class Main {
	public static void main(String[] args) {
		NewspaperPublisher newspaperPublisher = new NewspaperPublisher();
		
		Subscriber1 subscriber1 = new Subscriber1(newspaperPublisher);
		Subscriber2 subscriber2 = new Subscriber2(newspaperPublisher);
		Subscriber3 subscriber3 = new Subscriber3(newspaperPublisher);
		
		System.out.println("============신문 발행===========");
		
		newspaperPublisher.publish();
		
		System.out.println("==========구독자2 구독취소=======");
		
		subscriber2.unsubscribe();
		
		System.out.println("============신문 발행===========");
		
		newspaperPublisher.publish();
		
	}
}

출력결과

구독자1이 신문을 구독했습니다.
구독자2이 신문을 구독했습니다.
구독자3이 신문을 구독했습니다.
============신문 발행===========
신문을 발행하였습니다.
새로운 신문이 구독자 1에게 도착했습니다.
새로운 신문이 구독자 2에게 도착했습니다.
새로운 신문이 구독자 3에게 도착했습니다.
==========구독자2 구독취소=======
구독자2이 구독을 해지했습니다.
============신문 발행===========
신문을 발행하였습니다.
새로운 신문이 구독자 1에게 도착했습니다.
새로운 신문이 구독자 3에게 도착했습니다.

 

- 설명

 

newspaperPublisher를 생성하고, subscriber1,2,3이 생성자를 통해 각자 자기 자신을 newspaperPublisher의 옵저버로 등록한다

 

newspaperpublisher가 신문을 발행하면, 등록된 옵저버들에게 신문이 도착했다는 알림이 간다

 

만약 subscriber2가 구독을 해지하게 되면, newspaperPublisher가 신문을 발행해도 subscriber1,3에게만 신문이 도착했다는 알림이 가게 된다

 

이렇듯 객체의 상태가 변경되었을 때, 특정 객체에 의존하지 않으면서 상태의 변경을 관련된 객체들에게 통지하는 것이 가능해진다

 

장점 : 느슨한 결합도

- subject와 observer는 서로 독립적으로 재사용 가능

- 옵저버의 추가와 삭제가 자유로움

 

단점

- 특정 옵저버에게는 필요하지 않은 데이터까지 전송할 우려가 있음