Menu
CoddyTech

Mẫu Observer

Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 47 trên 64.

Mẫu Observer tạo ra mối quan hệ một với nhiều, trong đó một đối tượng (chủ thể) thông báo cho nhiều đối tượng (bên quan sát) khi trạng thái của nó thay đổi.

Đây là một lớp Subject đơn giản quản lý các observer:

class Subject:
    def __init__(self):
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

Đối tượng lưu danh sách các trình quan sát và có thể thông báo cho tất cả cùng lúc.

Tạo các lớp quan sát đơn giản:

class EmailNotifier:
    def update(self, message):
        print(f"Email sent: {message}")

class SMSNotifier:
    def update(self, message):
        print(f"SMS sent: {message}")

Mỗi observer có một phương thức update được gọi khi nhận thông báo.

Sử dụng mẫu observer:

# Tạo đối tượng chủ thể
news = Subject()

# Tạo các đối tượng quan sát
email = EmailNotifier()
sms = SMSNotifier()

# Thêm các đối tượng quan sát vào chủ thể
news.add_observer(email)
news.add_observer(sms)

# Thông báo cho tất cả đối tượng quan sát
news.notify("Breaking news: Python is awesome!")

Tạo một ví dụ thực tế về trình theo dõi giá cổ phiếu:

class Stock:
    def __init__(self, symbol, price):
        self.symbol = symbol
        self._price = price
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def set_price(self, price):
        self._price = price
        self.notify()
    
    def notify(self):
        for observer in self._observers:
            observer.update(self.symbol, self._price)

class Investor:
    def __init__(self, name):
        self.name = name
    
    def update(self, symbol, price):
        print(f"{self.name} notified: {symbol} is now ${price}")

# Sử dụng công cụ theo dõi cổ phiếu
apple_stock = Stock("AAPL", 150)

investor1 = Investor("Alice")
investor2 = Investor("Bob")

apple_stock.add_observer(investor1)
apple_stock.add_observer(investor2)

apple_stock.set_price(155)  # Thông báo cho tất cả nhà đầu tư

Đầu ra:

Email sent: Breaking news: Python is awesome!
SMS sent: Breaking news: Python is awesome!
Alice notified: AAPL is now $155
Bob notified: AAPL is now $155

Điểm chính: Mẫu Observer cho phép một đối tượng tự động thông báo cho nhiều đối tượng khác khi có thay đổi. Đối tượng chủ thể duy trì danh sách các đối tượng quan sát và gọi phương thức update của chúng khi cần. Mẫu này hữu ích cho thông báo, hệ thống sự kiện và giúp nhiều phần trong ứng dụng của bạn luôn đồng bộ.

challenge icon

Thử thách

Trung bình

Triển khai Observer Pattern bằng cách tạo một hệ thống theo dõi thời tiết. Bạn cần tạo hai lớp ở những vị trí được chỉ định trong code.

Bước 1: Tạo lớp WeatherStation

Viết lớp WeatherStation tại vị trí được ghi chú. Lớp này cần:

  • Kế thừa từ lớp Subject (dùng class WeatherStation(Subject):)
  • Khởi tạo với:
    • Gọi hàm khởi tạo của lớp cha bằng super().__init__()
    • Đặt nhiệt độ ban đầu là 0 bằng thuộc tính có một dấu gạch dưới self._temperature (quy ước của Python cho thuộc tính nội bộ)
  • Triển khai set_temperature(self, temperature):
    • Cập nhật thuộc tính nhiệt độ nội bộ
    • Gọi self.notify(self._temperature) để thông báo cho tất cả observer
  • Triển khai get_temperature(self):
    • Trả về giá trị nhiệt độ hiện tại

Bước 2: Tạo lớp WeatherDisplay

Viết lớp WeatherDisplay tại vị trí được ghi chú. Lớp này cần:

  • Kế thừa từ lớp Observer (dùng class WeatherDisplay(Observer):)
  • Khởi tạo với:
    • Nhận một tham số name
    • Lưu tên vào self.name
  • Triển khai update(self, temperature):
    • In thông báo cập nhật nhiệt độ theo chính xác định dạng bên dưới

Định dạng thông báo:

Khi màn hình nhận được thông tin cập nhật nhiệt độ, màn hình phải in chính xác:

Display [name]: Current temperature is [temperature]C

Ví dụ sử dụng:

# Create weather station and displays
station = WeatherStation()
phone_display = WeatherDisplay("Phone")
tablet_display = WeatherDisplay("Tablet")

# Attach displays to station
station.attach(phone_display)
station.attach(tablet_display)

# Update temperature - both displays will be notified
station.set_temperature(25.5)

# Output:
# Display Phone: Current temperature is 25.5C
# Display Tablet: Current temperature is 25.5C

Lưu ý quan trọng:

  • Các phương thức attach() và detach() đã được triển khai trong lớp cơ sở Subject, bạn không cần triển khai chúng hoặc gọi chúng trong lớp WeatherStation
  • Trong ví dụ sử dụng ở trên, người dùng lớp của bạn gọi station.attach(phone_display), không phải bên trong phần triển khai WeatherStation
  • WeatherStation chỉ cần gọi self.notify() khi nhiệt độ thay đổi, lớp cơ sở Subject sẽ xử lý phần còn lại
  • Tập trung triển khai ba phương thức bắt buộc trong WeatherStation và hai phương thức bắt buộc trong WeatherDisplay như mô tả ở trên

Tự làm thử

class Subject:
    def __init__(self):
        self._observers = []
    
    def attach(self, observer):
        self._observers.append(observer)
        
    def detach(self, observer):
        self._observers.remove(observer)
        
    def notify(self, data):
        for observer in self._observers:
            observer.update(data)
            
class Observer:
    def update(self, data):
        pass

# Viết lớp WeatherStation ở đây

# Viết lớp WeatherDisplay ở đây

quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Python online