Python
"-"
1. (Subject)
2. (Concrete Subject)
3. (Observer)
4. (Concrete Observer)
from abc import ABC, abstractmethod
from typing import List
#
class Observer(ABC):
@abstractmethod
def update(self, message: str):
""""""
pass
#
class Subject(ABC):
@abstractmethod
def register_observer(self, observer: Observer):
""""""
pass
@abstractmethod
def remove_observer(self, observer: Observer):
""""""
pass
@abstractmethod
def notify_observers(self):
""""""
pass
# -
class NewsPublisher(Subject):
def __init__(self):
self._observers: List[Observer] = []
self._latest_news = ""
def register_observer(self, observer: Observer):
""""""
if observer not in self._observers:
self._observers.append(observer)
print(f" {observer.__class__.__name__} ")
def remove_observer(self, observer: Observer):
""""""
if observer in self._observers:
self._observers.remove(observer)
print(f" {observer.__class__.__name__} ")
def notify_observers(self):
""""""
print(f"\n: {self._latest_news}")
for observer in self._observers:
observer.update(self._latest_news)
def publish_news(self, news: str):
""""""
self._latest_news = news
self.notify_observers()
def get_observer_count(self) -> int:
""""""
return len(self._observers)
# -
class EmailSubscriber(Observer):
def __init__(self, name: str):
self.name = name
def update(self, message: str):
""""""
print(f"[] {self.name} : {message}")
# -
class SMSSubscriber(Observer):
def __init__(self, name: str, phone: str):
self.name = name
self.phone = phone
def update(self, message: str):
""""""
print(f"[] {self.phone} - {self.name} : {message}")
# -
class AppPushSubscriber(Observer):
def __init__(self, username: str):
self.username = username
def update(self, message: str):
""""""
print(f"[] {self.username} : {message}")
from typing import List
#
class Observer(ABC):
@abstractmethod
def update(self, message: str):
""""""
pass
#
class Subject(ABC):
@abstractmethod
def register_observer(self, observer: Observer):
""""""
pass
@abstractmethod
def remove_observer(self, observer: Observer):
""""""
pass
@abstractmethod
def notify_observers(self):
""""""
pass
# -
class NewsPublisher(Subject):
def __init__(self):
self._observers: List[Observer] = []
self._latest_news = ""
def register_observer(self, observer: Observer):
""""""
if observer not in self._observers:
self._observers.append(observer)
print(f" {observer.__class__.__name__} ")
def remove_observer(self, observer: Observer):
""""""
if observer in self._observers:
self._observers.remove(observer)
print(f" {observer.__class__.__name__} ")
def notify_observers(self):
""""""
print(f"\n: {self._latest_news}")
for observer in self._observers:
observer.update(self._latest_news)
def publish_news(self, news: str):
""""""
self._latest_news = news
self.notify_observers()
def get_observer_count(self) -> int:
""""""
return len(self._observers)
# -
class EmailSubscriber(Observer):
def __init__(self, name: str):
self.name = name
def update(self, message: str):
""""""
print(f"[] {self.name} : {message}")
# -
class SMSSubscriber(Observer):
def __init__(self, name: str, phone: str):
self.name = name
self.phone = phone
def update(self, message: str):
""""""
print(f"[] {self.phone} - {self.name} : {message}")
# -
class AppPushSubscriber(Observer):
def __init__(self, username: str):
self.username = username
def update(self, message: str):
""""""
print(f"[] {self.username} : {message}")
def demo_basic_observer():
""""""
print("=== ===\n")
#
publisher = NewsPublisher()
#
email_user = EmailSubscriber("")
sms_user = SMSSubscriber("", "13800138000")
app_user = AppPushSubscriber("")
#
publisher.register_observer(email_user)
publisher.register_observer(sms_user)
publisher.register_observer(app_user)
print(f"\n: {publisher.get_observer_count()}")
#
publisher.publish_news("Python 3.12 ")
#
publisher.remove_observer(sms_user)
print(f"\n: {publisher.get_observer_count()}")
#
publisher.publish_news("")
#
if __name__ == "__main__":
demo_basic_observer()
""""""
print("=== ===\n")
#
publisher = NewsPublisher()
#
email_user = EmailSubscriber("")
sms_user = SMSSubscriber("", "13800138000")
app_user = AppPushSubscriber("")
#
publisher.register_observer(email_user)
publisher.register_observer(sms_user)
publisher.register_observer(app_user)
print(f"\n: {publisher.get_observer_count()}")
#
publisher.publish_news("Python 3.12 ")
#
publisher.remove_observer(sms_user)
print(f"\n: {publisher.get_observer_count()}")
#
publisher.publish_news("")
#
if __name__ == "__main__":
demo_basic_observer()
=== === EmailSubscriber SMSSubscriber AppPushSubscriber : 3 : Python 3.12 [] : Python 3.12 [] 13800138000 - : Python 3.12 [] : Python 3.12 SMSSubscriber : 2 : [] : [] :
#
class Stock:
""""""
def __init__(self, symbol: str, price: float):
self.symbol = symbol #
self._price = price #
self._history = [price] #
@property
def price(self) -> float:
return self._price
@price.setter
def price(self, value: float):
""""""
old_price = self._price
self._price = value
self._history.append(value)
return old_price, value
def get_price_change(self) -> float:
""""""
if len(self._history) < 2:
return 0.0
return ((self._history[-1] - self._history[-2]) / self._history[-2]) * 100
class StockMarket(Subject):
""" - """
def __init__(self):
self._observers: List[Observer] = []
self._stocks = {} # : {: Stock}
def register_observer(self, observer: Observer):
if observer not in self._observers:
self._observers.append(observer)
def remove_observer(self, observer: Observer):
if observer in self._observers:
self._observers.remove(observer)
def notify_observers(self, stock: Stock):
""""""
change = stock.get_price_change()
message = f"{stock.symbol}: ${stock.price:.2f} ({change:+.2f}%)"
for observer in self._observers:
observer.update(message)
def add_stock(self, symbol: str, initial_price: float):
""""""
self._stocks[symbol] = Stock(symbol, initial_price)
def update_stock_price(self, symbol: str, new_price: float):
""""""
if symbol in self._stocks:
stock = self._stocks[symbol]
old_price, current_price = stock.price, new_price
stock.price = new_price
#
if old_price != current_price:
self.notify_observers(stock)
class Investor(Observer):
""" - """
def __init__(self, name: str, interest_stocks: List[str] = None):
self.name = name
self.interest_stocks = interest_stocks or []
self.notifications = []
def update(self, message: str):
""""""
stock_symbol = message.split(":")[0]
#
if not self.interest_stocks or stock_symbol in self.interest_stocks:
self.notifications.append(message)
print(f" {self.name} : {message}")
def show_notifications(self):
""""""
print(f"\n=== {self.name} ===")
for notification in self.notifications:
print(f" - {notification}")
def demo_stock_market():
""""""
print("\n=== ===\n")
#
market = StockMarket()
#
market.add_stock("AAPL", 150.0)
market.add_stock("GOOGL", 2800.0)
market.add_stock("TSLA", 250.0)
#
investor1 = Investor("", ["AAPL", "GOOGL"])
investor2 = Investor("", ["TSLA"])
investor3 = Investor("")
#
market.register_observer(investor1)
market.register_observer(investor2)
market.register_observer(investor3)
#
print("...")
market.update_stock_price("AAPL", 152.5) # AAPL
market.update_stock_price("TSLA", 245.0) # TSLA
market.update_stock_price("GOOGL", 2820.0) # GOOGL
market.update_stock_price("AAPL", 151.0) # AAPL
#
investor1.show_notifications()
investor2.show_notifications()
investor3.show_notifications()
#
demo_stock_market()
class Stock:
""""""
def __init__(self, symbol: str, price: float):
self.symbol = symbol #
self._price = price #
self._history = [price] #
@property
def price(self) -> float:
return self._price
@price.setter
def price(self, value: float):
""""""
old_price = self._price
self._price = value
self._history.append(value)
return old_price, value
def get_price_change(self) -> float:
""""""
if len(self._history) < 2:
return 0.0
return ((self._history[-1] - self._history[-2]) / self._history[-2]) * 100
class StockMarket(Subject):
""" - """
def __init__(self):
self._observers: List[Observer] = []
self._stocks = {} # : {: Stock}
def register_observer(self, observer: Observer):
if observer not in self._observers:
self._observers.append(observer)
def remove_observer(self, observer: Observer):
if observer in self._observers:
self._observers.remove(observer)
def notify_observers(self, stock: Stock):
""""""
change = stock.get_price_change()
message = f"{stock.symbol}: ${stock.price:.2f} ({change:+.2f}%)"
for observer in self._observers:
observer.update(message)
def add_stock(self, symbol: str, initial_price: float):
""""""
self._stocks[symbol] = Stock(symbol, initial_price)
def update_stock_price(self, symbol: str, new_price: float):
""""""
if symbol in self._stocks:
stock = self._stocks[symbol]
old_price, current_price = stock.price, new_price
stock.price = new_price
#
if old_price != current_price:
self.notify_observers(stock)
class Investor(Observer):
""" - """
def __init__(self, name: str, interest_stocks: List[str] = None):
self.name = name
self.interest_stocks = interest_stocks or []
self.notifications = []
def update(self, message: str):
""""""
stock_symbol = message.split(":")[0]
#
if not self.interest_stocks or stock_symbol in self.interest_stocks:
self.notifications.append(message)
print(f" {self.name} : {message}")
def show_notifications(self):
""""""
print(f"\n=== {self.name} ===")
for notification in self.notifications:
print(f" - {notification}")
def demo_stock_market():
""""""
print("\n=== ===\n")
#
market = StockMarket()
#
market.add_stock("AAPL", 150.0)
market.add_stock("GOOGL", 2800.0)
market.add_stock("TSLA", 250.0)
#
investor1 = Investor("", ["AAPL", "GOOGL"])
investor2 = Investor("", ["TSLA"])
investor3 = Investor("")
#
market.register_observer(investor1)
market.register_observer(investor2)
market.register_observer(investor3)
#
print("...")
market.update_stock_price("AAPL", 152.5) # AAPL
market.update_stock_price("TSLA", 245.0) # TSLA
market.update_stock_price("GOOGL", 2820.0) # GOOGL
market.update_stock_price("AAPL", 151.0) # AAPL
#
investor1.show_notifications()
investor2.show_notifications()
investor3.show_notifications()
#
demo_stock_market()
1. GUI
#
button.on_click(handler1) #
button.on_click(handler2) #
#
button.on_click(handler1) #
button.on_click(handler2) #
#
2.
3.
4.
- UI
1.
import weakref
class SafeSubject(Subject):
def __init__(self):
self._observers = weakref.WeakSet() #
def register_observer(self, observer: Observer):
self._observers.add(observer)
class SafeSubject(Subject):
def __init__(self):
self._observers = weakref.WeakSet() #
def register_observer(self, observer: Observer):
self._observers.add(observer)
2.
import asyncio
class AsyncObserver(ABC):
@abstractmethod
async def update_async(self, message: str):
pass
class AsyncSubject:
async def notify_observers_async(self):
tasks = [observer.update_async(self._message)
for observer in self._observers]
await asyncio.gather(*tasks)
class AsyncObserver(ABC):
@abstractmethod
async def update_async(self, message: str):
pass
class AsyncSubject:
async def notify_observers_async(self):
tasks = [observer.update_async(self._message)
for observer in self._observers]
await asyncio.gather(*tasks)
3.
def safe_notify(self):
for observer in self._observers.copy(): #
try:
observer.update(self._message)
except Exception as e:
print(f" {observer} : {e}")
for observer in self._observers.copy(): #
try:
observer.update(self._message)
except Exception as e:
print(f" {observer} : {e}")
Python