파이썬에서 디자인 패턴 "Observer"를 배우십시오.

GoF의 디자인 패턴을 학습하는 소재로서, 서적 「 증보 개정판 Java 언어로 배우는 디자인 패턴 입문 」가 참고가 되는 것 같네요. 다만, 다루어지고 있는 실례는, JAVA 베이스이기 때문에, 자신의 이해를 깊게 하기 위해서도, Python에서 동등의 프랙티스에 도전해 보았습니다.

■ Observer 패턴(옵저버·패턴)



Observer 패턴이란, 프로그램내의 오브젝트의 이벤트( 이벤트)를 다른 오브젝트에 통지하는 처리로 사용되는 디자인 패턴의 일종.
통지하는 오브젝트측이, 통지되는 오브젝트측에 관찰(영: observe)되는 형태가 되는 것으로부터, 이렇게 불린다.
출판-구독형 모델이라고도 불린다. 암묵적 호출의 원칙과 관계가 깊다.
분산 이벤트 처리 시스템의 구현에도 사용된다. 언어에 따라서는, 이 패턴으로 취급되는 문제는 언어가 가지는 이벤트 처리 구문으로 처리된다.

UML class and sequence diagram





UML 클래스 diagram





(이상 위키피디아(Wikipedia)에서 인용)

□ 비망록


Observer 패턴에서는, 관찰 대상의 상태가 변화하면, 관찰자에게 통지되기 때문에, 상태 변화에 따른 처리를 기술할 때에 유효하다고 합니다.observer 라는 말의 본래의 의미는 「관찰자」입니다만, 실제로는 Observer 역은 능동적으로 「관찰」하는 것이 아니라, Subject 역으로부터 「통지」되는 것을 수동 적으로 기다리고 있는 것이 되므로, Publish-Subscribe 패턴이라고 불리는 일도 있다고 합니다.
확실히 publish(発行)subscribe(購読) 라는 표현이 적절하다고 생각했습니다.

■ "Observer" 샘플 프로그램



실제로 Observer 패턴을 활용한 샘플 프로그램을 움직여서 다음과 같은 동작의 모습을 확인하고 싶습니다.
  • 많은 수의 객체를 관찰자가 관찰하고 그 값을 표시하는 메커니즘입니다.
  • 표시 방법은 관찰자에 따라 다릅니다.
  • DigitalObserver는 숫자로 숫자를 표시합니다.
  • GraphicObserver는 간단한 그래프로 값을 표시합니다.
    $ python Main.py 
    DigitObservser: 30
    GraphicObserver:******************************
    DigitObservser: 48
    GraphicObserver:************************************************
    DigitObservser: 6
    GraphicObserver:******
    DigitObservser: 19
    GraphicObserver:*******************
    DigitObservser: 19
    GraphicObserver:*******************
    DigitObservser: 45
    GraphicObserver:*********************************************
    DigitObservser: 8
    GraphicObserver:********
    DigitObservser: 21
    GraphicObserver:*********************
    DigitObservser: 40
    GraphicObserver:****************************************
    DigitObservser: 6
    GraphicObserver:******
    DigitObservser: 1
    GraphicObserver:*
    DigitObservser: 9
    GraphicObserver:*********
    DigitObservser: 26
    GraphicObserver:**************************
    DigitObservser: 22
    GraphicObserver:**********************
    DigitObservser: 16
    GraphicObserver:****************
    DigitObservser: 10
    GraphicObserver:**********
    DigitObservser: 45
    GraphicObserver:*********************************************
    DigitObservser: 1
    GraphicObserver:*
    DigitObservser: 36
    GraphicObserver:************************************
    DigitObservser: 45
    GraphicObserver:*********************************************
    

    ■ 샘플 프로그램에 대해 자세히 알아보기



    Git 저장소에도 비슷한 코드가 있습니다.
    htps : // 기주 b. 이 m / 싹 / s dy _ f_로 し ん _ 파 rn / t ree /
  • 디렉토리 구성
  • .
    ├── Main.py
    └── observer
        ├── __init__.py
        ├── generator.py
        └── observer.py
    

    (1) Subject(피험자)의 역할


    Subject 역은, 「관찰되는 측」을 나타냅니다. Subject 역할은 관찰자 Observer 역할을 등록하는 메소드와 삭제하는 메소드를 가지고 있습니다. 또, 「현재의 상태를 취득하는」메소드도 선언되고 있습니다.
    샘플 프로그램에서는, NumberGenerator 클래스가, 이 역할을 노력합니다.

    observer/generator.py
    import random
    from abc import ABCMeta, abstractmethod
    
    class NumberGenerator(metaclass=ABCMeta):
        def __init__(self):
            self.__observers = []
    
        def addObserver(self, observer):
            self.__observers.append(observer)
    
        def deleteObserver(self, observer):
            self.__observers.remove(observer)
    
        def notifyObserver(self):
            for o in self.__observers:
                o.update(self)
    
        @abstractmethod
        def getNumber(self):
            pass
    
        @abstractmethod
        def execute(self):
            pass
    

    (2) ConcreteSubject(구체적인 피험자)의 역할


    ConcreteSubject 역은, 구체적인 「관찰되는 측」을 표현하는 역입니다. 상태가 변경되면, 그것이 등록되어 있다 Observer 역에 전합니다.
    샘플 프로그램에서는, RandomNumberGenerator 클래스가, 이 역할을 노력합니다.

    observer/generator.py
    class RandomNumberGenerator(NumberGenerator):
        def __init__(self):
            self.__number = 0
            super(RandomNumberGenerator, self).__init__()
    
        def getNumber(self):
            return self.__number
    
        def execute(self):
            for _ in range(20):
                self.__number = random.randint(0, 49)
                self.notifyObserver()
    

    (3) Observer (관찰자)의 역할


    Observer 역은, Subject 역으로부터 「상태가 변화했습니다」라고 가르쳐 주는 역입니다. 이를 위한 메소드가 update 입니다.
    샘플 프로그램에서는, Observer 클래스가, 이 역할을 노력합니다.

    observer/observer.py
    import time
    from abc import ABCMeta, abstractmethod
    
    class Observer(metaclass=ABCMeta):
        @abstractmethod
        def update(self, generator):
            pass
    

    (4) ConcreteObserver (구체적인 관찰자)의 역할


    ConcreteObserver 역할은 구체적인 Observer입니다. update 메소드가 불려 가면(자), 그 메소드안에서 Subject 역의 현재 상태를 취득합니다.
    샘플 프로그램에서는, DigitObserver 클래스와 GraphObserver 클래스가, 이 역할을 노력합니다.

    observer/observer.py
    class DigitObserver(Observer):
        def update(self, generator):
            print("DigitObservser: {0}".format(generator.getNumber()))
            time.sleep(0.1)
    
    
    class GraphObserver(Observer):
        def update(self, generator):
            print("GraphicObserver:", end='')
            count = generator.getNumber()
            for _ in range(count):
                print('*', end='')
            print("")
            time.sleep(0.1)
    

    (5) Client(의뢰인)의 역할



    샘플 프로그램에서는, startMain 메소드가, 이 역할을 노력합니다.

    Main.py
    from observer.observer import  DigitObserver, GraphObserver
    from observer.generator import RandomNumberGenerator
    
    def startMain():
        generator = RandomNumberGenerator()
        observer1 = DigitObserver()
        observer2 = GraphObserver()
        generator.addObserver(observer1)
        generator.addObserver(observer2)
        generator.execute()
    
    if __name__ == '__main__':
        startMain()
    

    ■ 참고 URL


  • 「Java 언어로 배우는 디자인 패턴 입문」을 끝내고(없음)
  • 좋은 웹페이지 즐겨찾기