Python 옵저버 패턴
Python 옵저버 패턴
옵저버 패턴(Observer Pattern) 이해하기
소프트웨어 개발에서 객체 간의 상호작용을 효율적으로 관리하는 것은 중요한 설계 과제 중 하나입니다. 이런 문제를 해결하기 위해 사용되는 디자인 패턴 중 하나가 바로 옵저버 패턴(Observer Pattern)입니다. 이번 글에서는 옵저버 패턴의 개념과 필요성, 그리고 Python 코드를 활용한 실제 구현 예제를 소개합니다.
1. 옵저버 패턴이란?
옵저버 패턴은 객체의 상태 변화를 관찰하고, 그 변화를 다른 객체들에게 자동으로 알리는 디자인 패턴입니다. 이 패턴을 통해 주체(Subject)와 옵저버(Observer) 간의 느슨한 결합(Loose Coupling)을 유지할 수 있습니다.
핵심 개념
- 주체(Subject)
- 상태를 관리하며, 옵저버들에게 상태 변화 이벤트를 알리는 역할을 합니다.
- 옵저버(Observer)
- 주체의 상태를 구독하고, 상태가 변경되었을 때 알림을 받아 필요한 작업을 수행합니다.
2. 왜 옵저버 패턴을 사용해야 할까?
객체 간의 결합도를 낮춤 옵저버 패턴을 사용하면 객체 간의 의존성을 낮추고 확장성을 높일 수 있습니다. 예를 들어, 주체는 옵저버가 몇 개인지 또는 어떤 작업을 수행하는지 알 필요가 없습니다.
상태 변화에 대한 자동 반응 주체의 상태가 변경되었을 때, 모든 구독자(옵저버)에게 자동으로 알림을 보내므로 수동으로 알림을 관리하지 않아도 됩니다.
3. 옵저버 패턴을 사용해야 하는 경우
- 객체 상태의 변경 사항을 다른 객체들에게 알릴 필요가 있을 때
- 예: 데이터 모델이 변경되었을 때 UI를 업데이트하는 경우.
- 여러 객체가 동일한 주체의 상태를 구독해야 할 때
- 예: 채팅 애플리케이션에서 새로운 메시지를 모든 사용자에게 알리는 경우.
4. Python으로 옵저버 패턴 구현하기
예제: 뉴스 구독 시스템
from abc import ABC, abstractmethod
from typing import List
# 1. 옵저버 인터페이스 정의
class Observer(ABC):
@abstractmethod
def update(self, message: str) -> None:
pass
# 2. 주체 클래스 정의
class NewsPublisher:
def __init__(self):
self._subscribers: List[Observer] = [] # 구독자 리스트
def subscribe(self, observer: Observer) -> None:
self._subscribers.append(observer)
def unsubscribe(self, observer: Observer) -> None:
self._subscribers.remove(observer)
def notify(self, message: str) -> None:
for subscriber in self._subscribers:
subscriber.update(message)
# 3. 구체적인 옵저버 구현
class EmailSubscriber(Observer):
def __init__(self, email: str):
self.email = email
def update(self, message: str) -> None:
print(f"Email to {self.email}: {message}")
class SMSSubscriber(Observer):
def __init__(self, phone_number: str):
self.phone_number = phone_number
def update(self, message: str) -> None:
print(f"SMS to {self.phone_number}: {message}")
class AppNotificationSubscriber(Observer):
def __init__(self, username: str):
self.username = username
def update(self, message: str) -> None:
print(f"App Notification to {self.username}: {message}")
# 4. 옵저버 패턴 사용 예시
if __name__ == "__main__":
# 주체 생성
= NewsPublisher()
publisher
# 구독자 생성
= EmailSubscriber("user@example.com")
email_subscriber = SMSSubscriber("010-1234-5678")
sms_subscriber = AppNotificationSubscriber("user123")
app_subscriber
# 구독자 등록
publisher.subscribe(email_subscriber)
publisher.subscribe(sms_subscriber)
publisher.subscribe(app_subscriber)
# 상태 변경 알림
"Breaking News: Design patterns are awesome!")
publisher.notify(
# 구독 해제
publisher.unsubscribe(sms_subscriber)
# 상태 변경 알림
"Update: Observer pattern explained!") publisher.notify(
5. 코드 설명
- 옵저버 인터페이스 (
Observer
)- 모든 구독자는
update
메서드를 구현해야 합니다. - 상태 변경 시 주체가 호출하여 알림을 전달합니다.
- 모든 구독자는
- 주체 (
NewsPublisher
)_subscribers
리스트를 통해 옵저버들을 관리합니다.subscribe
와unsubscribe
메서드로 옵저버를 추가하거나 제거합니다.notify
메서드를 통해 모든 구독자에게 메시지를 알립니다.
- 구체적인 옵저버 (
EmailSubscriber
,SMSSubscriber
,AppNotificationSubscriber
)- 각각 이메일, SMS, 앱 알림을 처리하는 구독자 클래스입니다.
- 패턴 사용 예시
- 뉴스 알림 시스템에서 구독자를 추가/제거하고, 주체 상태 변경 시 자동으로 메시지를 전송합니다.
6. 실행 결과
Email to user@example.com: Breaking News: Design patterns are awesome!
SMS to 010-1234-5678: Breaking News: Design patterns are awesome!
App Notification to user123: Breaking News: Design patterns are awesome!
Email to user@example.com: Update: Observer pattern explained!
App Notification to user123: Update: Observer pattern explained!
- 첫 번째 알림은 모든 구독자에게 전달됩니다.
- 두 번째 알림에서는 SMS 구독자가 제거되었으므로, 나머지 두 구독자에게만 전달됩니다.
7. 옵저버 패턴의 장점
느슨한 결합 주체와 옵저버 간의 의존성이 낮아 확장성과 재사용성이 높습니다.
자동화된 알림 주체 상태 변경 시 수동으로 알림을 관리할 필요가 없습니다.
유연성 런타임에 옵저버를 추가하거나 제거할 수 있습니다.
8. 옵저버 패턴의 단점
복잡도 증가 주체와 옵저버가 많아지면 시스템이 복잡해질 수 있습니다.
디버깅 어려움 옵저버 간의 의존 관계가 복잡한 경우, 디버깅이 어려울 수 있습니다.
마무리
옵저버 패턴은 객체 상태의 변경을 여러 객체에게 자동으로 알리기 위한 강력한 도구입니다. 뉴스 구독 시스템과 같은 실제 사례를 통해 이 패턴의 유용성을 확인해보았습니다.
옵저버 패턴은 특히 이벤트 기반 시스템이나 실시간 알림이 필요한 애플리케이션에서 매우 유용합니다.