• 파이썬으로 옵저버 패턴을 구현해보자

    2017. 9. 14. 23:47

    by. 위지원



     *** 옵저버 패턴이란 주체에 종속된 관찰자들에게 주체가 나 변경됨!을 자동으로 알리는 디자인 패턴으로 분산 이벤트 처리 시스템 구현시 사용한다



    코드를 구현해보자


    우선 옵저버 클래스를 구현한다.

    저번에 학습한대로 옵저버를 등록,해제 그리고 변경상태를 알릴 수 있또록 하는 notify가 있다.




    class Observer:
    def __init__(self):
    self.subscriber = []
    self.msg = ""

    def notify(self):
    for sub in self.subscriber:
    sub.msg = self.msg

    def register(self, observer):
    self.subscriber.append(observer)

    def unregister(self, observer):
    self.subscriber.remove(observer)


    그리고 이 옵저버로 부터 정보를 전달 받는 친구들이 있다. 옵저버는 객체가 변경되면 이 친구들에게 정보를 전달해주는것이다.

    얘네가 추가되면 이제 위의 옵저버에 있는 subcriber리스트에 추가되어서 옵저버에 종속적인 객체가될것이다.

    업데이트라는 메서드를 통해 위의 옵저버 객체가 가지고 있는 msg 를 출력하도록 코드가 구현되어있다.


    class subscriber:

    def __init__(self):
    msg = ""

    def update(self):
    print(self.msg)


     옵저버에 의해 관찰되는 객체도 구현해준다


    class Subject:
    def __init__(self):
    self.observer = []

    def notify_observer(self, info):
    for obs in self.observer:
    obs.msg = info

    def attach(self, observer):
    self.observer.append(observer)

    def dettach(self, observer):
    self.observer.remove(observer)


    이제 구독자 객체를 생성하고 


    sub1 = subscriber()
    sub2 = subscriber()
    sub3 = subscriber()


    이 구독자들을 옵저버에 추가해준다.


    ob = Observer()
    ob.register(sub1)
    ob.register(sub2)
    ob.register(sub3)


    그리고 옵저버에 의해 관찰될 객체에 옵저버를 등록시켜준다.


    sub = Subject()
    sub.attach(ob)


    그리고서 객체에서 옵저버에게 보낼 메세지를 등록시켜준 뒤 옵저버가 자기한테 추가되어진 구독자들에게 다시 알려주고 

    각 구독자들의 업뎃 메서드를 수행하면

    아래와 같이 결과가 나타난다.


    notify msg

    notify msg

    notify msg


    sub.notify_observer("notify msg")

    ob.notify()
    a.update()
    b.update()
    c.update()


    이것만으로는 살짝 이해가 안되어서 더 찾아보았다.





    이 코드는 더 직관적인것같다. 위키에서 본 다이어그램과 흡사하다 

    1.옵저버가 있고 이 옵저버를 구현한 각각의 옵저버들이 또 있다.

    2.이 옵저버에의해 관찰되는 주제 객체를 구현한 객체가 있다



    "니가바뀌는지 보는중이야!"[옵저버]=========(관찰중)========>[객체] "내가바뀌면 넌 자동으로 알아야해"

                    [옵저버구현N개] "바뀌면 나도알려줘!"



    우선 인터페이스를 선언해준다.


    class Subject:
    __metaclass__=ABCMeta

    @abstractmethod
    def register_observer(self):
    pass

    @abstractmethod
    def remove_observer(self):
    pass
    @abstractmethod
    def notify_observers(self):
    pass

    class Observer:
    @abstractmethod
    def update(self):
    pass



    그리고 위의 인터페이스를 구현한 주제와 옵저버를 구현한다.


    class ConcreteSubject(Subject):
    def __init__(self):
    self.state=""
    self.observer_list=[]

    def register_observer(self,observer):
    print ('register',observer)
    self.observer_list.append(observer)

    def remove_observer(self,observer):
    print ('remove',observer)
    self.observer_list.remove(observer)
    def notify_observers(self):
    print 'notify msg'
    class ConcreteObserver(Observer):
    def update(self):
    pass



    이게 기본 틀이다. 인터페이스를 선언하고 후에 그 인터페이스를 구현하고! 

    그래서 지난번에 느슨한 결합을 언급했던것같다. 느슨한결합은 블로거분이 아주쉽게 설명해주셧는데 상호작용하긴하는데 서로 잘 모른다는것이란다.



    실제로 구현해보았다. 상태가 변하면 메세지가 화면에 출력된다 


    from abc import ABCMeta, abstractmethod

    class Subject:
        __metaclass__ = ABCMeta

        @abstractmethod
        def register_observer(self):
            pass

        @abstractmethod
        def remove_observer(self):
            pass

        @abstractmethod
        def notify_observers(self):
            pass

    class Observer:

        @abstractmethod
        def update(self, temperature, humidity, pressure):
            pass

        @abstractmethod
        def register_subject(self, subject):
            pass


    class weejiwon(Subject):
        def __init__(self):
            super(weejiwon, self).__init__()
            self._observer_list = []
            self.happiness = 0
            self.sadness = 0

        def register_observer(self, observer):
            if observer in self._observer_list:
                return "Already exist observer!"
            
            self._observer_list.append(observer)
            return "Success register!"

        def remove_observer(self, observer):
            if observer in self._observer_list:
                _observer_list.remove(observer)
                return "Success remove!"

            return "observer does not exist."

        def notify_observers(self): #옵저버에게 알리는 부분 (옵저버리스트에 있는 모든 옵저버들의 업데이트 메서드 실행)
            for observer in self._observer_list:
                observer.update(self.happiness,self.sadness)

        def emotionalChanged(self):
            self.notify_observers() #감정이 변하면 옵저버에게 알립니다.

        def set_emotional(self, happiness,sadness):
            self.happiness=happiness
            self.sadness=sadness
            self.emotionalChanged()

    class Emotion(Observer):
        def update(self, happiness,sadness): #업데이트 메서드가 실행되면 변화된 감정내용을 화면에 출력해줍니다
            self.happiness=happiness
            self.sadness=sadness
            self.display()

        def register_subject(self, subject):
            self.subject = subject
            self.subject.register_observer(self)

        def display(self):
            print ('weejiwon Emotion happiness:',self.happiness,' sadness:',self.sadness)

    def test():
        weejiwonObj = weejiwon()
        EmotionObj=Emotion()
        EmotionObj.register_subject(weejiwonObj)


        weejiwonObj.set_emotional('good','good')
        weejiwonObj.set_emotional('Not good','Not good')
        weejiwonObj.set_emotional('Bad','Bad')

    if __name__ == '__main__':
        test()




    결과


    ('weejiwon Emotion happiness:', 'good', ' sadness:', 'good') ('weejiwon Emotion happiness:', 'Not good', ' sadness:', 'Not good') ('weejiwon Emotion happiness:', 'Bad', ' sadness:', 'Bad')