2017년/Python

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

위지원 2017. 9. 14. 23:47


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



코드를 구현해보자


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

저번에 학습한대로 옵저버를 등록,해제 그리고 변경상태를 알릴 수 있또록 하는 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')