Design Pattern

옵저버 패턴

우드의개발개발 2023. 7. 24. 13:29

옵저버 패턴 구성

옵저버 패턴의 구성은 다음과 같다. 2개의 인터페이스 그리고 각각의 인터페이스를 구현한 구상클래스로 파악할 수 있다. 

  • 옵저버 인터페이스
  • 주제 인터페이스
  • 주제클래스
  • 옵저버 클래스

주제 인터페이스(Subject Interface)

해당 인터페이스에서 최소한으로 가지고 있어야 할 변수와 메서드는 아래와 같다. 옵저버 명단부터 알아보자. 해당 배열에 들어가는 데이터 타입은 옵저버 객체이다. 옵저버 객체는 옵저버 인터페이스를 구현한 옵저버 객체를 의미한다. 해당 명단에 등록할 때에는 주제 인터페이스를 구현된 구상 클래스 주제 내 register 함수를 통해 옵저버 객체를 등록한다. 해당 명단에 옵저버 객체를 등록하는 이유는 notify 함수를 통해서 옵저버 객체 내부에 각각 구현된 update 함수를 호출하기 위함이다. 만약 옵저버 전체를 호출하는 notify 함수에서 특정 옵저버를 제외하고 싶다면 remove 함수를 통해서 옵저버 객체를 명단에서 제외하면 된다.

  • 변수
    • 옵저버 명단
      • 옵저버 명단을 등록하는 배열
  • 메서드
    • register
      • 옵저버 객체를 등록하는 함수
    • remove
      • 옵저버 객체를 제거하는 함수 
    • notify
      • 옵저버 명단에 등록된 옵저버 내부에 구현된 함수를 호출하는 함수 

옵저버 인터페이스(Observer Interface)

해당 인터페이스에서 최소한으로 가지고 있어야 할 메서드는 아래와 같다. update 함수는 주제 객체에서 notify 함수를 호출할 때 옵저버 명단에 있는 각각의 옵저버의 update 함수를 호출하는데 이때 옵저버 각각의 객체에서 구현한 로직이 실행된다. 여기서 짚고 넘어가야 할 부문은 주제에서 notify 함수를 호출할 때 해당 함수가 실행된다는 점이다.

  • 함수
    • update
      • 주제가 옵저버리스트를 돌면서 각각의 옵저버 객체 내부에 구현된 메소드를 호출하는데 그 때 호출되는 메서드이다.

주제

  • 주제 인터페이스를 구현한 구상 클래스. 구상 클래스란 구체적인 클래스의 줄임말. 추상적인 클래스와 비교되는 단어.

옵저버

  • 옵저버 인터페이스를 구현한 구상 클래스.

 

옵저버 패턴의 정리

  • 행동 패턴의 일종
  • 객체 간 일대 다 관계
  • 주제의 상태 변화 시 옵저버 명단에 등록된 옵저버들에게 자신의 notify 함수를 통해 옵저버의 update 함수를 통해 상태 변화를 반영
  • 해당 패턴의 목적은 객체 간 결합을 느슨하게 하기 위함
    • 주제의 상태가 변화하더라도 옵저버 객체의 코드가 수정되는 부문이 없음
  • 활용하는 곳
    • GUI Framework
    • Event handling
      • 특정 이벤트가 발생했을 때 해당 이벤트에 맞춰서 리스너들이 update 되어야 하는 상황
    • Publish-Subscribe system
      • Pub-Sub 아키텍처를 이해하는데 core한 부문으로 작용한다. Publisher 입장에서 모든 Subscriber 들에게 메세지를 발송할 때 Observer Pattern과 구조가 동일하다.
    • Database System
      • Database의 trigger 발생 시
    • Model-View-Controller
      • Model이 등록된 view들에게 변화에 대해서 공지한다.

옵저버 패턴 파이썬 코드로의 구현

from abc import *

### 옵저버 인터페이스
class ObserverInterface(metaclass=ABCMeta):
    @abstractmethod
    def __init__(self):
      pass

    @abstractmethod
    def update(self):
        pass

### 주제 인터페이스
class SubjectInteface(metaclass=ABCMeta):
  @abstractmethod
  def __init__(self):
    pass

  @abstractmethod
  def register(self, animal: ObserverInterface):
    pass

  @abstractmethod
  def remove(self, animal: ObserverInterface):
    pass

  @abstractmethod
  def notify(self):
    pass


### 디스플레이 인터페이스
class DisplayInterface(metaclass=ABCMeta):
  @abstractmethod
  def display(self):
    pass


### 주제 인터페이스를 상속받아 주제를 구현한 구상 클래스
class Subject(SubjectInteface):
  def __init__(self):
    self.observers = []
    self.name = "TOM"
    self.sex = "MALE"
    self.age  = "31"

  def get_name(self):
    return self.name

  def get_sex(self):
    return self.sex
  
  def get_age(self):
    return self.age

  def register(self, animal: ObserverInterface):
    self.observers.append(animal)

  def remove(self, animal: ObserverInterface):
    self.observers.remove(animal)

  def notify(self, name: str, sex: str, age: str):
    name = self.get_name()
    sex = self.get_sex()
    age = self.get_age()

    for animal in self.observers:
      animal.update(name, sex, age)


### 옵저버 인터페이스와 디스플레이 인터페이스를 상속받아 구현한 옵저버 구상클래스
class Cat(ObserverInterface, DisplayInterface):
  def __init__(self):
    self.name = None
    self.sex = None
    self.age = None

  def update(self, name: str, sex: str, age: str):    
    print('Cat Update Meow')
    self.name = name
    self.sex = sex
    self.age = age   
    self.display() 

  def display(self):
    print(f'Cat recived data: {self.name}, {self.sex}, {self.age}')
   

### 옵저버 인터페이스와 디스플레이 인터페이스를 상속받아 구현한 옵저버 구상클래스
class Dog(ObserverInterface, DisplayInterface):
    def __init__(self):
      self.name = None
      self.sex = None
      self.age = None

    def update(self, name: str, sex: str, age: str):
      print('Dog Update Bark')
      self.name = name
      self.sex = sex
      self.age = age
      self.display()

    def display(self):
      print(f'Dog recived data: {self.name}, {self.sex}, {self.age}')


owner = Subject()
cat = Cat()
dog = Dog()

owner.register(cat)
owner.register(dog)
owner.remove(cat)

owner.notify(owner.name, owner.sex, owner.age)

'Design Pattern' 카테고리의 다른 글

데코레이터 패턴  (0) 2023.07.25
전략패턴  (0) 2023.07.24
추상 팩토리 패턴  (0) 2023.06.09