모르는게 많은 개발자

[디자인 패턴] Observer Pattern 개념/예제 본문

디자인패턴

[디자인 패턴] Observer Pattern 개념/예제

Awdsd 2020. 12. 19. 16:14
반응형

1. 옵저버 패턴

옵저버 패턴은 객체의 상태 변화를 관찰하는 관찰자들(Observer) 목록을 '이벤트를 발생시키는 이벤트 객체'에 등록하여 이벤트가 발생할 때마다 메소드를 통해 관찰자들(Observer) 객체들에게 알려주어 그에 맞게 행위를 하는 디자인 패턴이다.

 

아래 UML 다이어그램을 보자

Observer라는 인터페이스에는 notify()라는 함수가 정의되있다. notify()는 이벤트가 발생했을 때 처리할 행위를 정의한다.

Subject(이벤트 발생 객체)에는 observerCollection이 존재하는데 여기에 Observer객체들이 저장된다.

그리고 notifyObservers()Observer 객체들의 목록들의 notify()를 실행해 이벤트 발생에 따른 처리를 각 Observer에게 전달한다.

registerObserver(observer)는 observer을 등록, unregisterObserver(observer)는 특정 observer를 리스트에서 제거한다.


2. 옵저버 패턴 예제

아래 예제에서는 Publisher(이벤트 발생 객체)와 Observer를 인터페이스로 구현해 옵저버 패턴을 구현했다.

Publisher에는 다음과 같은 메소드가 정의되어 있다.

  • addObserver -> 관찰자 객체 추가
  • deleteObserver -> 관찰자 객체 삭제
  • notifyObservers -> 관찰자들에게 이벤트 발생 전달

Observer에는 다음과 같은 메소드만 정의되어 있다.

  • notify -> 이벤트 발생 감지
main 테스트 프로세스
  1. Publisher 구현체인 PlayController 객체와 Observer 구현체인 ObserverA, ObserverB를 생성
  2. Observer 구현체는 생성자를 통해 publisher 객체에 등록된다.
  3. PlayController가 setFlag()를 통해 이벤트를 발생시키고, Observer 구현체들의 notify를 실행한다.(이벤트 감지)
  4. Observer 구현체들은 myActControl()을 통해 이벤트 감지의 따른 행위를 실행.

여기서 중요한 것은 Observer구현체는 외부에서 직접적으로 접근하지 않고 오로지 Publisher를 통해 접근된다.

즉, Observer구현체가 이벤트를 감지한다는 것은 Publisher에서 이벤트가 발생했을 때 notifyObservers()를 통해 모든 Observer 목록의 notify()를 실행해준다는 뜻이다.

//이벤트 발생시키는 객체 인터페이스
interface Publisher {
    //관찰자 객체 추가
    public void addObserver(Observer o);
    //관찰자 객체 삭제
    public void deleteObserver(Observer o);
    //관찰자들에게 이벤트 발생 전달
    public void notifyObservers();
}

//관찰자 객체 인터페이스
interface Observer {
    //이벤트 발생에 따른 행위
    public void notify(boolean play);
}
//이벤트 객체 구현
class PlayController implements Publisher {
    private List<Observer> observers = new ArrayList<>();
    private boolean play;
    private Observer myOb;

    @Override
    public void addObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void deleteObserver(Observer o) {
        observers.remove(o);
    }

    //옵저버들에게 변경사항을 전달
    @Override
    public void notifyObservers() {
        //옵저버 목록들에게 이벤트 전달
        for (int i=0; i<observers.size(); i++) {
            observers.get(i).notify(play);
        }
    }

    //이벤트 발생 함수
    public void setFlag(boolean play) {
        this.play = play;
        notifyObservers();
    }

    public boolean getFlag() {
        return play;
    }
}
//관찰자 객체 구현
class ObserverA implements Observer {
    private boolean bPlay;
    private Publisher publisher;

    public ObserverA(Publisher publisher) {
        this.publisher = publisher;
        publisher.addObserver(this);
    }

    @Override
    public void notify(boolean play) {
        this.bPlay = play;
        myActControl();
    }

    public void myActControl() {
        if (bPlay) {
            System.out.println("MyClassA : 동작을 시작합니다.");
        } else {
            System.out.println("MyClassA : 동작을 정지합니다.");
        }
    }
}

///관찰자 객체 구현
class ObserverB implements Observer {
    private boolean bPlay;
		
    //객체를 생성할 때 
    public ObserverB(Publisher publisher) {
        publisher.addObserver(this);
    }

    //이벤트 감지
    @Override
    public void notify(boolean play) {
        this.bPlay = play;
        myActControl();
    }

    //행위
    public void myActControl() {
        if (bPlay) {
            System.out.println("MyClassB : 동작을 시작합니다.");
        } else {
            System.out.println("MyClassB : 동작을 정지합니다.");
        }
    }
}
//main 테스트
public class ObserverTest {
    public static void main(String[] args) {
        PlayController playController = new PlayController();
        Observer ob1 = new ObserverA(playController);
        Observer ob2 = new ObserverB(playController);
				//이벤트 발생
        playController.setFlag(true);

        //옵저버 삭제
        playController.deleteObserver(ob1);
        playController.setFlag(false);
    }
}

결과
MyClassA : 동작을 시작합니다.
MyClassB : 동작을 시작합니다.
MyClassB : 동작을 정지합니다.

3. Listener 예제

Android 프로젝트를 진행하면 button을 클릭했을 때 발생을 행위를 정의하는 listener를 구현한다.

listener도 옵저버 패턴을 이용해 구현된 경우이다. Button은 publisher, OnClickListener은 Observer 역할을 한다.

Button buttonRed = (Button) findViewById(R.id.buttonRed);
buttonRed.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick(View view) {
        textView1.setText("Red") ;
        textView1.setBackgroundColor(Color.rgb(255, 0, 0));
    }
});

Listener를 예제로 구현하면 다음과 같다.

interface ButtonPublisher {
    public void setButtonListener(Button.OnClickListener listener);
    public void notifyButton();
}


class Button implements ButtonPublisher {
    OnClickListener listener;

    @Override
    public void setButtonListener(OnClickListener listener) {
        this.listener = listener;
    }

    @Override
    public void notifyButton() {
        listener.Onclick();
    }

    interface OnClickListener {
        void Onclick();
    }
}

//main 테스트
public class ObserverTest {
    public static void main(String[] args) {
        Button button1 = new Button();
        //함수형 인터페이스를 통해 익명함수로 Click 이벤트 구현
        button1.setButtonListener(() -> {
            System.out.println("버튼 클릭");
        });
        button1.notifyButton();
    }
}
결과
버튼 클릭
반응형
Comments