옵서버 패턴

런던행·2020년 8월 9일
0

디자인 패턴

목록 보기
5/8

행위패턴 개요

  • 생성패턴은 객체가 생성되는 방식이 중요
  • 구조패턴은 객체와 클래스를 합쳐 더 큰 기능을 구현
  • 행위패턴은 이름 그대로 객체의 역할에 초점을 둔다. 더 큰 기능을 구현하기 위한 객체간의 상호 작용을 중요시 한다.

옵서버 패턴 이해

  • 옵서버 패턴에서 객체(서브젝트)는 자식(옵서버)의 목록을 유지하며 서브젝트가 옵서버에 정의된 메소드를 호출할 때마다 옵서버에 이를 알린다.

옵서버 패턴의 구성원

  • 서브젝트(subject): 서브젝트는 옵서버를 관리한다. 옵서버는 Subject클래스의 register(), deRegister()메소드를 호출해 자신을 등록한다, 서브젝트는 여러 옵서버를 관리한다.
  • 옵서버(observer): 서브젝트를 감시하는 객체를 위한 인터페이스를 제공한다. 서브젝트의 상태를 알 수 있도록 ConcreateObserver가 구현해야 하는 메소드를 정의한다.

간단한 옵서버 디자인 패턴

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

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

    def notifyAll(self, *args, **kwargs):
        for observer in self.__observers:
            observer.notify(self, *args, **kwargs)

class Observer1:
    def __init__(self, subject):
        subject.register(self)

    def notify(self, subject, *args):
        print(type(self).__name__, '::Got', args, 'From', subject)

class Observer2:
    def __init__(self, subject):
        subject.register(self)

    def notify(self, subject, *args):
        print(type(self).__name__, "::Got", args, 'From', subject)

subject = Subject()
observer1 = Observer1(subject)
observer2 = Observer2(subject)

subject.notifyAll('notification!!! ')

옵서버 패턴 사용 사례

뉴스 에이전시를 옵서버 패턴으로 구현해보자, 뉴스 에이전시는 일반적으로 여러 곳에서 뉴스를 모아 구독자에게 전달한다.

  • 서브젝트의 행동은 NewsPublisher클래스에 구현한다.
  • NewsPublisher는 구독자가 구현할 인터페이스를 제공한다.
  • Observer는 attach() 메소드를 통해 자신을 NewsPublisher에 등록하고 detach() 메소드로 등록을 취소한다.
  • Subscribers()는 Subject에 등록된 구독자 목록을 반환한다.
  • notifiySubscriber()는 NewsPublisher에 등록된 모든 구독자에게 알림을 보낸다.
class NewsPublisher:
    def __init__(self):
        self.__subscribers = []
        self.__latestNews = None

    def attach(self, subscriber):
        self.__subscribers.append(subscriber)

    def detach(self):
        self.__subscribers.pop()

    def subscribers(self):
        return [type(x).__name__ for x in self.__subscribers]

    def notifySubscribers(self):
        for sub in self.__subscribers:
            sub.update()

    def addNews(self, news):
        self.__latestNews = news

    def getNews(self):
        return "Got News", self.__latestNews

from abc import ABCMeta, abstractmethod

class Subscriber(metaclass=ABCMeta):

    @abstractmethod
    def update(self):
        pass


class SMSSubscriber(Subscriber):
    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__, self.publisher.getNews())


class EmailSubscriber(Subscriber):
    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__, self.publisher.getNews())

if __name__ == '__main__':
    news_publisher = NewsPublisher()

    for subscriber in [SMSSubscriber, EmailSubscriber]:
        subscriber(news_publisher)

    news_publisher.addNews('new News!! he is gone')
    news_publisher.notifySubscribers()

    news_publisher.addNews('new News!! second!!')
    news_publisher.notifySubscribers()

SMSSubscriber ('Got News', 'new News!! he is gone')
EmailSubscriber ('Got News', 'new News!! he is gone')
SMSSubscriber ('Got News', 'new News!! second!!')
EmailSubscriber ('Got News', 'new News!! second!!')

profile
unit test, tdd, bdd, laravel, django, android native, vuejs, react, embedded linux, typescript

0개의 댓글