아무거나

[Design Pattern] Observer Pattern 본문

Java & Kotlin/Java

[Design Pattern] Observer Pattern

전봉근 2020. 1. 5. 18:45
반응형

옵저버 패턴(Observer Pattern)

옵저버 패턴을 통하여 이벤트 발생객체 외부에서 처리 할 수 있다.

 

 

Target 객체가 Observer 인터페이스를 가지고 있어서 notify()에서 update()를 호출해서 해당 Observer나 Target 객체에 상태변경(이벤트처리된것을 확인하는 패턴

옵저버 패턴 예시 - 1

가장 기본적인 옵저버 패턴을 구현하자

Button 클래스를 생성한다.
[Button.java]

package com.bkjeon.observer;

public class Button {

    // notify
    public void onClick() {
        if (onClickListener != null) {
            onClickListener.onClick(this);
        }
    }

    // Observer Interfacse
    public interface OnClickListener {
        public void onClick(Button button);
    }

    private OnClickListener onClickListener;

    // setObserver
    public void setClickListener(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }
}

메인 클래스를 작성하자.
[Main.java]

package com.bkjeon.observer;

public class Main {

    public static void main(String[] args) {
        Button button = new Button();

        button.setClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(Button button) {
                System.out.println(button + "is Clicked");
            }
        });
        button.onClick();
    }

}

실행결과

...Button@27d6c5e0is Clicked

옵저버 패턴 예시 - 2

자바에서 기본적으로 옵저버 패턴을 구현할 때 제공하는 클래스와 인터페이스를 이용해서 구현하자.

해당 API는 Java9 버전부터 Deprecated가 되었으므로 참고만 하자. (https://docs.oracle.com/javase/9/docs/api/java/util/Observable.html)

  • Observer: update함수가 있는데 여기서 받는 매개변수는 어떤것이 업데이트 되었는지(=Observable) 그리고 변경사항 혹은 어떤 이벤트인지(=Observer)를 매개변수로 받고 있다.
  • Observable: Observer 할 수 있는 클래스를 구현가능하게 해주는 클래스

먼저 Observable를 상속받은 Button 클래스를 구현하자
[Button.java]

package com.bkjeon.observer.example2;

import java.util.Observable;

public class Button extends Observable {

    public void onClick() {
        setChanged();
        notifyObservers();
    }

}

메인 클래스를 작성하자.
[Main.java]

package com.bkjeon.observer.example2;

import java.util.Observable;
import java.util.Observer;

public class Main {

    public static void main(String[] args) {
        Button button = new Button();

        button.addObserver(new Observer() {
            @Override
            public void update(Observable observable, Object o) {
                System.out.println(observable + " is Clicked");
            }
        });

        button.onClick();
        button.onClick();
        button.onClick();
    }

}

옵저버 패턴 예시 - 3

아래 목록을 사용하여 더 실용적으로 구현

  • 제네릭
  • 델리게이트
  • 내부에 옵저버를 넣는다.

먼저 클래스 내부의 멤버변수로 사용할 Observable 클래스를 구현하자.
[Observable.java]

package com.bkjeon.observer.example3;

import java.util.Vector;

public class Observable<T> {

    private boolean changed = false;
    private Vector<Observer<T>> obs = new Vector();

    public Observable() {
    }

    public synchronized void addObserver(Observer<T> o) {
        if (o == null) {
            throw new NullPointerException();
        } else {
            if (!this.obs.contains(o)) {
                this.obs.addElement(o);
            }

        }
    }

    public synchronized void deleteObserver(Observer<T> o) {
        this.obs.removeElement(o);
    }

    public void notifyObservers() {
        this.notifyObservers(null);
    }

    public void notifyObservers(T arg) {
        Vector<Observer<T>> arrLocal;

        synchronized(this) {
            if (!changed) {
                return;
            }

            arrLocal = (Vector<Observer<T>>) obs.clone();
            clearChanged();
        }

        for (Observer<T> observer: arrLocal) {
            observer.update(this, arg);
        }
    }

    public synchronized void deleteObservers() {
        this.obs.removeAllElements();
    }

    public synchronized void setChanged() {
        this.changed = true;
    }

    protected synchronized void clearChanged() {
        this.changed = false;
    }

    public synchronized boolean hasChanged() {
        return this.changed;
    }

    public synchronized int countObservers() {
        return this.obs.size();
    }

    public interface Observer<T> {
        void update(Observable<T> o, T org);
    }

}

그 다음 Button을 구현하고 델리게이트를 사용해보자.
[Button.java]

package com.bkjeon.observer.example3;

import com.bkjeon.observer.example3.Observable.Observer;

public class Button {

    public Button() {
        observable = new Observable<String>();
    }

    private Observable<String> observable;

    public void addObserver(Observer<String> o) {
        observable.addObserver(o);
    }

    public void notifyObservers() {
        observable.notifyObservers(null);
    }

    public void onClick() {
        observable.setChanged();    // 중요(변경되었다는걸 알림)
        notifyObservers();
    }

}

메인 클래스를 구현하자.
[Main.java]

package com.bkjeon.observer.example3;

public class Main {

    public static void main(String[] args) {
        Button button = new Button();
        button.addObserver(new Observable.Observer<String>() {
            @Override
            public void update(Observable<String> o, String org) {
                System.out.println(o + " is clicked");
            }
        });

        button.onClick();
        button.onClick();
        button.onClick();
    }

}

실행결과

com.bkjeon.observer.example3.Observable@15aeb7ab is clicked
com.bkjeon.observer.example3.Observable@15aeb7ab is clicked
com.bkjeon.observer.example3.Observable@15aeb7ab is clicked

 

참고: https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard

반응형

'Java & Kotlin > Java' 카테고리의 다른 글

[Design Pattern] State Pattern  (0) 2020.01.10
[Design Pattern] Mediator Pattern  (0) 2020.01.08
[Design Pattern] Facade Pattern  (0) 2020.01.04
[Design Pattern] Chain of Responsibility Pattern  (0) 2020.01.04
[Design Pattern] Visitor Pattern  (0) 2020.01.01
Comments