Mẫu Strategy
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 48 trên 64.
Mẫu chiến lược (Strategy Pattern) xác định một họ thuật toán, đóng gói từng thuật toán và cho phép thay thế chúng cho nhau. Bạn có thể chuyển đổi thuật toán trong khi chương trình đang chạy mà không cần thay đổi đoạn code phía máy khách.
Dưới đây là các lớp chiến lược đơn giản cho những phương thức thanh toán khác nhau:
class CreditCard:
def pay(self, amount):
return f"Paid ${amount} with Credit Card"
class PayPal:
def pay(self, amount):
return f"Paid ${amount} with PayPal"
class Bitcoin:
def pay(self, amount):
return f"Paid ${amount} with Bitcoin"Mỗi chiến lược đều triển khai cùng một phương thức (pay) nhưng có cách hoạt động khác nhau.
Tạo một lớp ngữ cảnh sử dụng các chiến lược:
class ShoppingCart:
def __init__(self):
self.total = 0
self.payment_strategy = None
def add_item(self, price):
self.total += price
def set_payment_strategy(self, strategy):
self.payment_strategy = strategy
def checkout(self):
return self.payment_strategy.pay(self.total)Lớp ngữ cảnh có thể chuyển đổi giữa các chiến lược thanh toán khác nhau.
Dùng mẫu chiến lược (strategy pattern):
cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)
# Dùng chiến lược thanh toán bằng thẻ tín dụng
cart.set_payment_strategy(CreditCard())
print(cart.checkout())
# Chuyển sang chiến lược thanh toán bằng PayPal
cart.set_payment_strategy(PayPal())
print(cart.checkout())Tạo một ví dụ khác với các chiến lược sắp xếp:
class BubbleSort:
def sort(self, data):
return f"Bubble sorted: {sorted(data)}"
class QuickSort:
def sort(self, data):
return f"Quick sorted: {sorted(data)}"
class Sorter:
def __init__(self, strategy):
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def sort_data(self, data):
return self.strategy.sort(data)
# Sử dụng các chiến lược sắp xếp khác nhau
numbers = [3, 1, 4, 1, 5]
sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))
sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))Đầu ra:
Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]Điểm chính: Strategy Pattern cho phép bạn thay đổi thuật toán khi chương trình đang chạy. Hãy định nghĩa các chiến lược khác nhau với cùng một giao diện, rồi để lớp ngữ cảnh chọn chiến lược cần dùng. Nhờ vậy, code của bạn linh hoạt và dễ mở rộng bằng các thuật toán mới mà không cần thay đổi code hiện có.
Thử thách
Trung bìnhTriển khai một chiến lược BitcoinPayment mới cho hệ thống mua sắm của chúng ta.
Nhiệm vụ của bạn:
- Tạo lớp BitcoinPayment triển khai PaymentStrategy
- Lớp này cần nhận wallet_address trong hàm khởi tạo
- Phương thức pay cần in chính xác:
Paying $X using Bitcoin wallet: Y, trong đó X là số tiền và Y là địa chỉ ví - Phương thức pay cần trả về True sau khi in
- Viết hàm (function) main để:
- Tạo một giỏ hàng
- Thêm một máy tính xách tay giá $1200 và một tai nghe giá $100 vào giỏ hàng
- Tạo một BitcoinPayment với địa chỉ ví "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
- Đặt chiến lược thanh toán này cho giỏ hàng
- Gọi phương thức checkout
Code khởi đầu đã có if __name__ == "__main__": ở cuối. Bạn không cần tự thêm dòng này. Đây là quy ước của Python, đảm bảo hàm main() chỉ chạy khi bạn thực thi trực tiếp tệp (không phải khi một module khác nhập tệp đó). Chỉ cần định nghĩa hàm main(), khối lệnh có sẵn sẽ tự động gọi hàm.
Làm theo cấu trúc tương tự như trong các ví dụ của bài học.
Tự làm thử
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number, expiry_date, cvv):
self.card_number = card_number
self.expiry_date = expiry_date
self.cvv = cvv
def pay(self, amount):
print(f"Paying ${amount} using Credit Card: {self.card_number}")
return True
class PayPalPayment(PaymentStrategy):
def __init__(self, email, password):
self.email = email
self.password = password
def pay(self, amount):
print(f"Paying ${amount} using PayPal account: {self.email}")
return True
class ShoppingCart:
def __init__(self):
self.items = []
self.payment_strategy = None
def add_item(self, item, price):
self.items.append({"item": item, "price": price})
def set_payment_strategy(self, payment_strategy):
self.payment_strategy = payment_strategy
def checkout(self):
total = sum(item["price"] for item in self.items)
if self.payment_strategy:
return self.payment_strategy.pay(total)
else:
raise ValueError("No payment strategy set")
# Tạo lớp (class) chiến lược BitcoinPayment tại đây
if __name__ == "__main__":
main()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
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnhTự luyện tập: Trình biên dịch Python online