[디자인패턴] 옵저버 패턴 (observer pattern)

in #kr-dev6 years ago (edited)

자 2개의 객체를 머리속에 떠올려보자. 예를 들자면, 아들과 아빠. 아빠 입장에서 아들을 키운다는 것은 꽤나 번거로운 일이다. 예를 들자면, 배가 고프면 밥을 차려줘야 되고, 졸리면 재워줘야 되고, 화장실이 급하면 보내줘야 한다. 아들이 알아서 이런 일들을 해준다면 참 좋을텐데 그렇지 않을 때가 많다. 왜냐하면 아들의 주 업무는 노는 것이지 기타 잡무가 아니기 때문이다. 그렇기 때문에 아빠는 아들의 상태를 확인하고 상태에 변화에 따라 적절한 행동을 취해야 한다.

정리하면 아들은 어떤 사건(event)을 발생시키고, 아빠는 관찰(observer)하다가 사건이 발생하면 이를 수습하는 구조이다. 사건을 발생시키는 객체를 이벤트 객체, 관찰하는 객체를 옵저버 객체라 부를 수 있을 것이다.

이렇듯, 옵저버 패턴은 객체 쌍이 존재하고, 한 객체의 상태 변화에 따라 다른 객체의 행동이 정해질 때 사용한다. 객체를 감시하는 행위가 필수적이기 때문에 옵저버(observer; 관찰자)라는 용어가 사용된다.

구현 방식은 여러가지가 있는데, 콜백 함수를 이용해서 구현해보자.

콜백

객체의 상태가 변하면, 변했다고 관찰자에게 알려주어야 한다. 이를 구현하기 위해 두가지가 필요하다. 첫째, 객체의 상태가 변하는 것을 사건, 즉 이벤트로 구체화하고 이를 함수형태로 구현한다. 둘째, 관찰자에게 알려주기 위해 관찰자를 제어하는 함수를 호출한다. 이러한 함수를 콜백 함수라 한다.

콜백은 이벤트 객체가 옵저버 객체의 함수를 호출해서 메시지를 전달하는 것이다. 그러기 위해서는 관찰자는 미리 호출될 함수를 등록한다. 등록되어 있는 함수를 호출해서 메시지를 전달하는 것이기 때문에 콜백(callback)이라 부른다.

먼저 이벤트 객체를 구현해보자. 파이썬에서 이를 구현하는 것은 여러 방법이 있지만, 간편하게 하려면 list 클래스에 call 함수를 구현해서 가능하다.

class Event(list):
    def __call__(self, *args, **kargs):
        for f in self:
            f(*args, **kargs)

이렇게 하면 Event 객체에 함수를 등록하고 call해서 등록된 함수를 호출할 수 있다.

e = Event()
def foo():
    print('bar')
e.append(foo)
e()
# output : bar

이벤트 콜백 예제 : 아빠와 아들

서두의 예제처럼 아빠와 아들 객체를 간단히 만들어보자. 아들 클래스는 뭔가 상태가 안좋아지만 화내는 사건을 일으킨다. 그 화 안에는 원인이 메시지로 담겨 있다.

class Child():
    anger = Event()
    def bad(self):
        self.anger('hungry')
        self.anger('sleepy')
        self.anger('thirsty')

아빠 클래스는 상황이 펼쳐지면 어떻게는 처리하고자 한다. 아마 말로만 말이지. care! 한다고 말한다.

class Father():
    def care(self, situation):
        print('care %s' % situation)

아들과 아빠 객체를 만들고, 아들 객체의 화나는 이벤트에 아빠의 care 함수를 등록한다.

c = Child()
f = Father()
c.anger.append(f.care)

c.bad()

그러면 아빠는 나름 observer하다가 아들이 화가 나면 care할 수 있게 된다.

# output
# care hungry
# care sleepy
# care thirsty

이벤트-콜백을 loose하게 하고 싶다면..

메시지 큐를 이용해서 IPC하면 된다. 이럴 때는 pub-sub 패턴이라 부른다.

참고

python 이벤트 구현 : https://stackoverflow.com/a/2022629


Sponsored ( Powered by dclick )
[kr-title] 현실이 드라마보다 더하면 더했지

덜하지 않다는걸 이 사건을 보면서 느끼게 되었네요;; kr-title이란?

Sort:  

Congratulations @tmkor! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You distributed more than 8000 upvotes. Your next target is to reach 9000 upvotes.

You can view your badges on your Steem Board and compare to others on the Steem Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

The Steem community has lost an epic member! Farewell @woflhart!
SteemitBoard - Witness Update
Do not miss the coming Rocky Mountain Steem Meetup and get a new community badge!
Vote for @Steemitboard as a witness to get one more award and increased upvotes!