본문 바로가기

Language/JAVA

[JAVA] 옵저버 패턴 (Observer pattern)

1. 옵저버 패턴 (Observer pattern)

- 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록해 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴

- 주로 분산 이벤트 핸들링 시스템을 구현하는데 사용된다.

- 주체 객체 + 상태의 변경을 알아야 하는 관찰 객체가 존재하며 1:1 또는 1:N의 관계가 될 수 있다.

 

옵저버 패턴의 구조 [1]

  • Subject : 이벤트를 발생시키는 주체, 관찰 대상 객체
  • Observer : 이벤트를 관찰하는 대상, 이벤트가 발생하면 콜백을 받아 notify 함수를 통해 Subject가 발행한 메시지 이외에도, 옵서버 자신이 생성한 인자값을 하위 Observer에게 전달
  • ConcreateObserver : notify 함수를 통해 이벤트가 발생했을 때 처리할 각자의 동작을 정의

   

   1-1. 옵저버 패턴의 장점 [2]

   - 실시간으로 한 객체의 변경사항을 다른 객체에 전파할 수 있다.

   - 느슨한 결함으로 시스템이 유연하고 객체 간의 의존성을 제거할 수 있다. 

 

   1-2. 옵저버 패턴의 단점 [2]

   - 너무 많이 사용하게 되면 상태 관리가 힘들 수 있다.

   - 데이터 배분에 문제가 생기면 자칫 큰 문제로 이어질 수 있다. [2]

 

   1-3. 옵저버 패턴의 구현 (JAVA) [1]

   

   (1) Java에서는 기본으로 제공하는 Observable 클래스와 Observer 인터페이스를 이용하여 좀 더 쉽게 구현 가능

   *하지만 Observable 객체는 JAVA 9부터 Deprecated 되었음*

 

  EventSouce.java

package obs;
import java.util.Observable; // 이 부분이 옵저버에게 신호를 보내는 주체입니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class EventSource extends Observable implements Runnable
{
    public void run()
    {
        try
        {
            final InputStreamReader isr = new InputStreamReader( System.in );
            final BufferedReader br = new BufferedReader( isr );
            while( true )
            {
                final String response = br.readLine();
                setChanged();
                notifyObservers( response );
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

 

  ResoponseHandler.java

package obs;

import java.util.Observable;
import java.util.Observer; /* 여기가 옵저버 */

public class ResponseHandler implements Observer
{
    private String resp;
    public void update (Observable obj, Object arg)
    {
        if (arg instanceof String)
        {
            resp = (String) arg;
            System.out.println("\nReceived Response: "+ resp );
        }
    }
}

 

  myApp.java

/* 여기서부터가 프로그램 시작점 */
package obs;

public class MyApp
{
    public static void main(String args[])
    {
        System.out.println("Enter Text >");

        // 이벤트 발행 주체를 생성함 - stdin으로부터 문자열을 입력받음
        final EventSource evSrc = new EventSource();

        // 옵저버를 생성함
        final ResponseHandler respHandler = new ResponseHandler();

        // 옵저버가 발행 주체가 발행하는 이벤트를 구독하게 함
        evSrc.addObserver( respHandler );

        // 이벤트를 발행시키는 쓰레드 시작
        Thread thread = new Thread(evSrc);
        thread.start();
    }
}

  * Observable [3]

  - setChanged() : 객체가 변경된 것을 표시하는 메서드

  - notifyObservers() : 객체가 변경된 경우 모든 Observer에게 알리는 메서드

 

  - addObserver() : 객체에 Observer 추가

 

  *Observer [4]

  - update() : 객체가 변경될 때 호출되는 메서드

 

  (2) 리스너 사용 [5]

 

Subject

public interface Subject {
	public void registerObserver(Observer observer); //Observer 등록
	public void unregisterObserver(Observer observer); //Observer 해제
	public void notifyObservers(String msg); //이벤트 발생 시 Observers들에게 알려주기
}

import java.util.ArrayList;
import java.util.List;

public class YouTuber implements Subject {
	private List<Observer> subscriberList; //Observers를 관리할 List
	
	public YouTuber() {
		subscriberList = new ArrayList<>();
	}
	
    //Subject 인터페이스의 기능들 구현
	@Override
	public void registerObserver(Observer observer) {
		subscriberList.add(observer);
	}

	@Override
	public void unregisterObserver(Observer observer) {
		subscriberList.remove(observer);
	}

	@Override
	public void notifyObservers(String msg) {
		for (Observer observer : subscriberList) {
			observer.notifySubscriber(msg);
		}
	}
}

 

Observer

public interface Observer {
	public void notifySubscriber(String msg);
}

public class SubscriberA implements Observer {

	@Override
	public void notifySubscriber(String msg) {
		System.out.println(this.getClass() + " : " + msg);
	}
}

public class SubscriberB implements Observer {

	@Override
	public void notifySubscriber(String msg) {
		System.out.println(this.getClass() + " : " + msg);
	}
}

 

Main

public class Main {

	public static void main(String[] args) {
		YouTuber youTuber = new YouTuber();
		Observer subscriberA = new SubscriberA();
		Observer subscriberB = new SubscriberB();
		
		System.out.println("subscriberA 구독 등록");
		youTuber.registerObserver(subscriberA);
		System.out.println("subscriberB 구독 등록");
		youTuber.registerObserver(subscriberB);
		
		youTuber.notifyObservers("New Video Upload!");
	}
}

 

참고자료

[1] 옵서버 패턴 : https://ko.wikipedia.org/wiki/%EC%98%B5%EC%84%9C%EB%B2%84_%ED%8C%A8%ED%84%B4

[2] [Design Pattern] 옵저버 패턴(Ovserver Pattern)에 대하여 : https://coding-factory.tistory.com/710

[3] Observable (Java Platform SE 7) : https://docs.oracle.com/javase/7/docs/api/java/util/Observable.html

[4] Observer (Java Platform SE 7) : https://docs.oracle.com/javase/7/docs/api/java/util/Observer.html

[5] 옵저버 패턴(Observer Pattern) : https://sorjfkrh5078.tistory.com/140

'Language > JAVA' 카테고리의 다른 글

[Java] Enum  (0) 2024.01.29
[JAVA] 싱글톤 패턴 (Singleton pattern)  (0) 2022.12.04