제 홈페이지의 모든 글은 anti-nhn license에 따릅니다.



자바 디자인 패턴 11 - Observer

1. Observer 패턴은..

어떤 클래스에 변화가 일어났을 때, 다른 클래스에 통보해 주는 패턴입니다. 통보를 하는 "어떤 클래스"가 Observable 이고, 통보를 받는 "다른 클래스"는 Observer입니다. Observable은 여러개의 Observer를 가질 수 있습니다. Observable이 "담임 떴다"를 외치면, Observer은 알아서 그에 걸맞는 행동을 합니다. 어떤 Observer는 만화책을 덮고 교과서를 꺼내고 어떤 Observer는 흘린 침 닦고 일어나서 공부하는 척하고 또 어떤 Observer는 먹던 도시락 치우고 창문 열어 환기를 시킵니다. Observable은 "담임 떴다"까지만 알려주지 "담임 떴으니깐, 누구는 어찌하고 누구는 저찌해라~" 까지 상세한 지시는 하지 않습니다.

2. 예제

---------------- 변화를 통보하는 Observable -------------

package ch11_Observer;
import java.util.Observable;
public class Watcher extends Observable {
    public void action(String string) {
        System.out.println("======="+string+"========");
        setChanged();
        notifyObservers(string);
    }
}

---------------- 변화를 통보받는 직원 -------------

package ch11_Observer;
import java.util.Observable;
import java.util.Observer;
public class Employee implements Observer {
    private String desc;
    public Employee(String desc) {
        this.desc = desc;
    }
    public void update(Observable o, Object arg) {
        if (o instanceof Watcher) {
            System.out.println(desc + "이 일하는 척");
        }
    }
    public String getDesc() {
        return desc;
    }
}

---------------- 변화를 통보받는 사장 끄나풀 -------------

package ch11_Observer;
import java.util.Observable;
import java.util.Observer;
public class Spy implements Observer {
    private Employee employee;
    public Spy(Employee employee) {
        this.employee = employee;
    }
    public void update(Observable o, Object arg) {
        if (o instanceof Watcher) {
            System.out.println("고자질쟁이가 "+employee.getDesc() +"이 놀고 있었다고 고자질.");
        }
    }
}

---------------- 테스트 클래스 -------------

package ch11_Observer;
public class Test {
    public static void main(String[] args) {
        Watcher watcher = new Watcher();
        Employee pc1 = new Employee("만화책보는 놈");
        Employee pc2 = new Employee("퍼질러 자는 놈");
        Employee pc3 = new Employee("포카치는 놈");
        //spy는 pc3을 보고 있음.
        //요놈은 꼰질르기의 대가
        Spy spy = new Spy(pc3);
        
        watcher.addObserver(pc1);
        watcher.addObserver(pc2);
        watcher.addObserver(pc3);
        watcher.addObserver(spy);
        
        watcher.action("사장 뜸.");
        watcher.deleteObserver(pc3);
        watcher.deleteObserver(spy);
        
        watcher.action("사장 뜸.");
    }
}

---------------- 테스트 결과 -------------

=======사장 뜸.========
고자질쟁이가 포카치는 놈이 놀고 있었다고 고자질.
포카치는 놈이 일하는 척
퍼질러 자는 놈이 일하는 척
만화책보는 놈이 일하는 척
=======사장 뜸.========
퍼질러 자는 놈이 일하는 척
만화책보는 놈이 일하는 척

일단 테스트 클래스만 보세요.
사장이 오는 지 감시하는 Watcher가 하나 있습니다. 그리고 3명의 Employee와 사장 끄나풀인 1명의 Spy가 있습니다. 얘네들은 전부 Watcher한테 사장 뜨면 알려달라고 얘기해 놓습니다. addObserver() 가 Observer로 등록하는 부분입니다.
각각의 Employee 들은 사장이 뜨면, 하던 일 멈추고 일하는 척을 합니다. Spy는 사장이 뜨면, 누가 놀고 있었다고 꼰지릅니다. Employee와 Spy는 같은 통보(사장이 떴다는 것)을 받지만 하는 일은 전혀 다릅니다. 이렇게 같은 통보에 전혀 다른 Observer 들을  붙여 버릴 수도 있습니다.
테스트 코드와 테스트 결과를 보면, observer를 등록한 순서와 통보를 받는 순서가 일치하지 않는 것을 알 수 있습니다. 통보를 받는 순서는 등록 순서와 무관합니다.
사장이 처음 떴을 때, "포카치는 놈"은 Spy한테 고자질 당해서 짤렸습니다. 짤렸기 때문에 더 이상 사장이 뜨던 말던 관심 없습니다. 그래서 Watcher에 Observer로 더 이상 등록되어 있을 필요가 없어졌습니다. 또, Spy는 잘했다고 포상휴가 갑니다. 얘도 더 이상 사장이 뜨는 지 안 뜨는지 통보 받을 필요가 없어졌습니다. 그래서 얘네 둘은 Watcher에 등록된 Observer 리스트에서 제거합니다. 색칠된 deleteObserver() 가 제거하는 부분입니다.
그래서 두 번째로 사장이 떴을 때는 "만화책 보는 놈"과 "퍼질러 자는 놈"만 통보를 받습니다.

다음은 Employee 클래스를 봅시다.
Observer 인터페이스를 구현하고 있습니다. Observer 인터페이스에는 update(Observable , Object) 메쏘드가 정의되어 있습니다.
첫번째 인자 Observable은 update를 호출해준 Observable 을 말합니다. 여기서는 Watcher 클래스가 되겠습니다. 하나의 Observer는 여러 개의 Observable에 등록될 수가 있습니다. "만화책 보는 놈"의 경우는 사장이 떠도 통보를 받아야겠지만, 신간 만화책이 나왔을 때도 통보를 받아야 합니다. 각기 다른 통보인 만큼 할 일이 달라지겠지요. 그러나, update 메쏘드를 각각의 Observable에 대응하도록 여러 개를 만들 수 없기 때문에 어떤 일인지를 Observable을 받아서 파악하고, 그에 걸맞는 행동을 합니다. 예제에서는 그 Observable이 단지 Watcher 클래스의 인스턴스인지 체크하는 방식으로 구현했습니다.
두번째 인자 Object를 통해서는 구체적인 정보를 받을 수 있습니다. 

이번에는 Watcher 클래스를 봅시다.
일단 Observable이란는 클래스를 상속받습니다. Observable 에는 몇 가지 메쏘드가 있습니다만 여기서는 두가지만 썼습니다. setChanged()와 notifyObservers() 입니다. setChanged() 는 변화가 일어났다는 것을 알리는 겁니다. 변화가 일어나지 않으면, 굳이 Observer 들에게 알릴 필요가 없습니다. 예를들어, Watcher는 무조건 감시하고 있는 클래스이기 때문에 잡상인이 뜨던가 사장이 뜨던가 다 압니다. 하지만, 잡상인이 떴을 경우는 Observer들에게 알릴 필요가 없습니다. 사장이 떴을 때만 setChanged()를 호출하고, Observer들에게 알립니다. (사장인지 아닌 지를 판단하는 로직은 코드가 길어져서 뺐습니다.) setChanged()가 호출되지 않고 notifyObservers()가 호출되면, 아무일도 일어나지 않습니다.
다음에 notifyObservers() 메쏘드가 있는데, 이 메쏘는 오버로드되어있습니다. notifyObservers()와 notifyObservers(Object) 두 가지가 있습니다. Object에는 어떤 일이 일어났는지 상세 정보를 담을 수 있습니다. 사장이 떴는지, 부장이 떴는 지 정도의 정보를 담을 수 있겠지요. notifyObservers()는 notifyObservers(null) 과 같습니다.
어찌되었건 notifyObservers(Object)가 호출이 되면, Observer들에게 전부 알립니다. 그러면, Observer들은 각각 자기가 가진 update() 메쏘드가 호출됩니다.

3. Observer 의 특징

말이 Observer이지 단지 Observerable에게 통보를 받는 입장입니다.
Observer 들은 Observable에 추가 삭제가 자유롭습니다. Observable 입장에서는 어떤 Observer인지 신경쓰지 않습니다. 단지 어떤 일이 일어났다는 통보만을 합니다. 통보에 대한 반응은 전적으로 Observer가 합니다. update() 메쏘드가 Observer에 있고, notifyObservers() 메쏘드가 Observable에 있는 것이 바로 그런 얘깁니다.

4. JAVA API에 있는 Observer

또, GUI 쪽 얘기를 꺼내게 되는군요. GUI에 있는(awt, swing, swt 등등 전부 비슷합니다.) 각종 버튼, 텍스트 등에 add머시기Listener 메쏘드 들이 잔뜩 있습니다. 이벤트가 일어나면, 뭔가를 호출하라는 것이지요. 예제에서 설명한 것과는 인터페이스가 다소 상이하긴 합니다.
GUI의 event는 Observer 패턴으로 구현되어 있어 이벤트 추가 삭제가 매우 자유롭습니다. 

by 삼실청년 | 2007/11/02 16:40 | 컴터질~ | 트랙백 | 핑백(2) | 덧글(17)

트랙백 주소 : http://iilii.egloos.com/tb/3902774
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at java design patt.. at 2017/05/31 09:26

... 디자인 패턴 9 11. 자바 디자인 패턴 11 – Observer&nbsp ... more

Linked at 자바 디자인 패턴 종류 &#8.. at 2017/09/26 09:15

... r 9. 자바 디자인 패턴 9 – Chain of Responsibility 10. 자바 디자인 패턴 10 – Facade 11. 자바 디자인 패턴 11 – Observer 12. 자바 디자인 패턴 12 – Prototype 13. 자바 디자인 패턴 13 – Flyweight 14. 자바 디자인 패 ... more

Commented by Mr.신 at 2010/01/18 17:00
Observer 패턴 설명에 있어서... 걸작입니다.
Commented by 삼실청년 at 2010/01/22 10:07
저걸 쉽게 이해하신다면, 수업시간에 딴 짓 좀 제대로 하신 게 아닐까 싶네요^^
사람은 경험에 바탕해서 생각하지요ㅋㅋㅋ
머.. 저라고 별다르단 건 아닙니다.. 그냥 그렇다는 거지요^^
Commented by Mr.40 at 2012/04/01 18:36
감사합니다 도움이 많이 되었습니다...^^
Commented by 삼실청년 at 2012/04/12 22:46
넹^^ 찾아주셔서 감사합니다.
Commented by 샹스 at 2013/07/16 11:20
설명 잘 들었어요...!! 그런데 이전에 만드신 자료네요!! 그래도 엄청 도움이 됩니다.
Commented by 삼실청년 at 2013/07/19 10:23
그러네요. 얼마 안 된 거 같은데 세월 참 빠르네요.
도움이 되셨길 바래요. ^^
Commented by kalkin at 2013/09/23 14:43
감사합니다. 많은도움이 되었습니다.
Commented by 삼실청년 at 2013/10/05 04:03
^^ 도움이 되셨길 바래요.
Commented by tjrgus21 at 2013/10/18 10:06
좋은 정보 감사합니다. 적절한 상황 예시와
예제 소스까지 감사합니다 ^^
Commented by 삼실청년 at 2013/11/18 14:38
냐하하~ 버려진 곳이라 답변이 늦네요.
도움이 되셨길 바래요^^
Commented by limecode at 2013/11/25 17:35
패턴명을 바꿀 필요가 있겠네요. 망보기 패턴!.
웃으면서 유익한 정보 갖고갑니다.
하나씩 읽으며 여기까지 왔는데..여태껏 본 패턴 설명중 가장 이해가 잘되네요.감사합니다아~~~ㅋ
나머지 패턴도 후딱 다 읽어야겠네요~~
Commented by 삼실청년 at 2013/12/11 01:03
넹^^ 도움이 되셨길 바래요.
Commented by 히히히 at 2014/09/24 19:16
진짜 너무 쉽게 설명해주셨네용 잘 보고갑니다~^^
Commented by 삼실청년 at 2015/01/22 21:23
넹^^ 이글이 젤 잘팔리는 글 중 하나인듯..ㅋ
Commented by 년청실삼 at 2016/01/17 21:50
크 설명참 맛깔나게 잘하시는듯하네요
맛으로 표현하자면 감칠맛나게 설명도 재밌고 일상생활에서 겪어본예를 바탕으로해주시고 혹은 흔히접하거나 쉽게 알 수 있는예를 사용하시니 머리에 쏙쏙박히네요 예제를통해 이게 어떤패턴인지를 바탕으로 깔고들어가니깐
p.s.2016병신년의 첫댓글!
Commented by 감사 at 2016/06/05 17:06
디자인 패턴 책을 보는 데 구자왜 이렇게 하지라는 생각에 이해를 못했는 데 이걸보나 이해되네요 책을 괜히 샀네요 ;;; 감사합니다
Commented by kluge at 2017/08/01 13:38
구글링하던중 너무 좋은글을 보고는 댓글을 남깁니다 ^^ 감사합니다.

:         :

:

비공개 덧글

◀ 이전 페이지          다음 페이지 ▶