티스토리 뷰

옵저버 패턴은 한 객체(Subject)의 상태가 변할 때, 그 객체에 의존하는 다른 객체들에 자동으로 데이터가 갱신되는 1 : n 의 의존성 관계를 갖는 형태를 의미한다.

아래 클래스 다이어그램을 보자



주제 인터페이스는 옵저버를 등록, 삭제, 상태 변경을 옵저버에게 전달하는 메소드를 추상메소드로 가지고 있다. 

그렇기 때문에 주제 클래스를 구현해야 사용할 수 있다. 옵저버 클래스도 인터페이스이를 구현해야만 옵저버로서 사용이 가능하다.

그 이유는, 주제 클래스는 옵저버 인터페이스를 구현하고 있는 클래스만을 옵저버로 인식하고 등록할 수 있기 때문이다. 

옵저버 인터페이스만 구현한다면 어떤 객체든 옵저버가 될 수 있다. 이 부분이 정말 중요하다! 

주제 객체가 옵저버에 대해 아는 정보는 오직, 옵저버 인터페이스를 구현하고 있다는 사실뿐이다. 

그리고 옵저버 객체는 주제 객체의 상태 변경에 대해 데이터를 전달받는 입장이기 때문에 옵저버에 대한 정보를 알 필요가 없다.

이 두 객체는 상호작용을 하고 있지만, 서로에 대해 잘 모르고, 그렇기 때문에 느슨하게 결합된 상태이다. 

또한 주제객체가 옵저버를 등록/삭제를 할 때, 주제 객체와 옵저버 객체에 대해 변경할 필요가 없다.

현재 이 두 객체는 서로 의존성이 최소화된 상태이다.


하지만, 여기서 의문을 품을 수 있다. 옵저버 객체가 일방적으로 데이터를 push 받는 것이 아닌, pull 방식으로 가져올 수는 없을까?

일방적으로 push를 받게되면 두 가지 단점이 있다.


 1. 주제 객체에 의존하는 옵저버 객체가 많을 때, 모든 옵저버 객체에게 상태 변경에 대한 정보를 전달하기 때문에 특정 옵저버에게는 상태변경이 

    무의미할 수 있다. 예를들어, 주제객체는 온도/습도/미세먼지/날씨 등의 기상정보를 측정하는 객체하고 하자. 그리고 옵저버 객체는 온도 디스플레이, 

    습도 디스플레이, 미세먼지 디스플레이다. 만약, 온도가 변경되었다면, 주제객체는 모든 온도, 습도, 미세먼지 옵저버 객체에게 온도변화에 대한 정보를 전달한다.

    그렇다면, 미세먼저와 습도 디스플레이에게는 무의미한 상태변경이지 않는가? 그렇다면 옵저버 객체가 getter를 통해 데이터를 가져오는 것이 좋지 않을까?


 2. 주제 객체가 확장되어 날씨 정보도 측정이 가능하다고 하면, 옵저버 객체에게 상태변화에 대한 정보를 보내는 메소드를 수정을 해야 한다.

    만약, 옵저버 객체가 getter를 통해 데이터를 가져간다면, 상태를 전달하는 메소드를 수정하지 않아도 되지 않을까?


이런 부분을 해결하기 위한 것이 자바에서 이미 구현이 되어있다. Observable 클래스와 Observer 인터페이스를 봐보자! (Pull & Push 방식 모두 제공)


앞서 소개된 옵저버 패턴과 차이점은 아래와 같다.

 1. 주제 인터페이스가 Observable 클래스로 바뀌었다. 이전에는 옵저버를 등록/삭제/상태전달이 추상메소드로 구현되었지만, 이제는 구현된 메소드로
    상속만 받으면 사용할 수 있다. 이 부분은 단점이 될 수있다. 자바는 다중상속이 지원되지 않기 때문에 주제 객체는 다른 클래스를 상속받을 수 없다.

 2. setChanged() 메소드가 있다. 주제객체에서 상태 변화가 있다면, setChanged() 메소드가 주제 객체의 상태를 변경한다음에, notifyObserver() 메소드를 통해

    상태 변화를 옵저버 객체에게 전달한다. setChanged() 메소드는 옵저버의 상태변화의 기준을 정의할 수 있다.

    만약 setChanged() 메소드가 없다면 주제객체의 온도가 0.001도가 변경할 때마다 옵저버 객체에게 전달을 해야한다. 

    setChanged() 메소드는 주제객체가 옵저버 객체에게 상태를 전달할 때의 유연성을 제공해준다는 장점을 가지고 있다.

 3. Pull 방식으로 옵저가 필요한 데이터만 getter 할 수 있다. 

    Push 방식은 notifyObserver(Object arg) 를 호출한다. Object 에는 상태 변경된 데이터들이 저장되어 있다.

    결국은 모든 옵저버의 update() 메소드에 변경된 정보를 전달하여 호출한다.

    반면, pull 방식은 notifyObserver() 메소드를 호출하고, 전달된 데이터는 null 값으로 되어 있다. 그렇기 때문에 모든 옵저버의 update() 메소드를 호출할 때

    단지 상태가 변경되었다는 사실만 전달하게 된다. 그리고 상태 변경을 인지한 각각의 옵저버는 필요에 따라 getter 메소드를 통해 데이터를 가져온다.


 


 



개인적으로 Push 보다는 Pull 방식이 더 효율적이라고 생각한다. 그 이유는 아래와 같다.

 1. Push 방식과 동일하게 느슨한 결합이 지원된다.

 2. Push 일 때, 주제객체는 모든 옵저버 객체에게 상태에 대한 변경 데이터를 전달해야 하기 때문에 모든 옵저버가 필요한 데이터를 보내야 한다.

    옵저버 입장에서는 불필요한 데이터를 받게 된다. 그러나 Pull 방식은 옵저가 필요한 데이터만 받을 수 있다.


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함