Tối ưu hóa mã Python - Trường hợp thực tế: Hệ thống đặt món nhà hàng
By JoeVu, at: 13:07 Ngày 15 tháng 11 năm 2024
Thời gian đọc ước tính: __READING_TIME__ minutes


1. Giới thiệu
Mã code lộn xộn, chứa đầy các câu lệnh if-else lồng nhau, thường xuất hiện trong các ứng dụng thực tế khi chúng trở nên phức tạp hơn. Theo thời gian, điều này khiến hệ thống khó bảo trì, gỡ lỗi và mở rộng hơn. Trong bài viết này, chúng ta sẽ giải quyết một trường hợp như vậy: một hệ thống đặt món nhà hàng, và chỉ ra cách tái cấu trúc nó bằng thiết kế hướng đối tượng có thể đơn giản hóa logic và cải thiện khả năng mở rộng.
2. Vấn đề
Hệ thống đặt món nhà hàng của chúng ta xử lý:
- Giảm giá dựa trên loại khách hàng (VIP, lần đầu tiên, v.v.).
- Phụ phí cho các đơn đặt hàng giao hàng, ăn tại chỗ hoặc mang đi.
- Thuế thay đổi theo vị trí.
Đây là triển khai lộn xộn ban đầu:
class Order:
def __init__(self, order_type, customer_type, base_price, location=None):
self.order_type = order_type
self.customer_type = customer_type
self.base_price = base_price
self.location = location
def calculate_total(self):
total = self.base_price
# Giảm giá dựa trên loại khách hàng
if self.customer_type == "VIP":
total *= 0.9 # Giảm giá 10%
elif self.customer_type == "first-time":
total *= 0.85 # Giảm giá 15%
# Phụ phí dựa trên loại đơn hàng
if self.order_type == "delivery":
if self.location == "urban":
total += 5
elif self.location == "rural":
total += 10
elif self.order_type == "dine-in":
total += 2
# Thuế
if self.location in ["urban", "rural"]:
total *= 1.05
elif self.order_type == "takeout":
total *= 1.02
# Các điều kiện bổ sung
if self.customer_type == "VIP" and self.order_type == "dine-in":
total -= 5 # Khách VIP được giảm 5$ cho ăn tại chỗ
return total
order = Order(order_type="delivery", customer_type="VIP", base_price=100, location="rural")
print(f"Tổng giá đơn hàng: ${order.calculate_total():.2f}")
Tại sao mã này tệ:
-
Logic lồng nhau sâu:
- Nhiều cấp câu lệnh
if-else
khiến mã khó đọc và khó theo dõi.
- Logic bị phân tán khắp phương thức, khiến khó hiểu mã làm gì chỉ bằng một cái nhìn.
- Nhiều cấp câu lệnh
-
Khả năng mở rộng thấp:
- Thêm các loại khách hàng, giảm giá hoặc loại đơn hàng mới yêu cầu sửa đổi phương thức đã phức tạp này.
- Cách tiếp cận này vi phạm Nguyên tắc Mở-Đóng (mã nên mở rộng nhưng đóng để sửa đổi).
- Thêm các loại khách hàng, giảm giá hoặc loại đơn hàng mới yêu cầu sửa đổi phương thức đã phức tạp này.
-
Vi phạm Trách nhiệm Đơn nhất:
- Phương thức
calculate_total
xử lý giảm giá, phụ phí và thuế ở một nơi, dẫn đến một "phương thức thần" làm quá nhiều việc.
- Bất kỳ thay đổi nào ở một phần của logic đều có nguy cơ làm hỏng các phần không liên quan của phương thức.
- Phương thức
-
Khó kiểm thử:
- Kiểm thử hàm này yêu cầu bao phủ nhiều điều kiện cho loại khách hàng, loại đơn hàng và vị trí.
- Bất kỳ lỗi nào trong một khối điều kiện đều có thể lan truyền qua toàn bộ phương thức.
- Kiểm thử hàm này yêu cầu bao phủ nhiều điều kiện cho loại khách hàng, loại đơn hàng và vị trí.
-
Khó bảo trì:
- Nếu quy tắc kinh doanh thay đổi (ví dụ: tỷ lệ giảm giá hoặc thuế mới), bạn phải cẩn thận xác định vị trí và cập nhật phần mã liên quan.
- Nguy cơ gây ra lỗi trong quá trình thay đổi như vậy là cao.
- Nếu quy tắc kinh doanh thay đổi (ví dụ: tỷ lệ giảm giá hoặc thuế mới), bạn phải cẩn thận xác định vị trí và cập nhật phần mã liên quan.
-
Kết nối chặt chẽ:
- Tất cả logic kinh doanh được kết nối chặt chẽ trong phương thức
calculate_total
.
- Nó không thể được sử dụng lại ở nơi khác, chẳng hạn như trong công cụ báo cáo hoặc dịch vụ khác.
- Tất cả logic kinh doanh được kết nối chặt chẽ trong phương thức
3. Tái cấu trúc
Để giải quyết các vấn đề được xác định trong triển khai ban đầu, chúng ta tái cấu trúc hệ thống bằng cách sử dụng mẫu chiến lược và thiết kế hướng đối tượng. Những cải tiến này tập trung vào việc phân chia logic thành các lớp có thể tái sử dụng, tuân theo các nguyên tắc chính như tính mô đun, đóng gói và tách biệt mối quan tâm.
Những cải tiến chính trong tái cấu trúc
1. Giới thiệu các lớp chiến lược cho Giảm giá
- Logic giảm giá được trích xuất thành các lớp riêng biệt dựa trên loại khách hàng (ví dụ:
VIPDiscount
,FirstTimeDiscount
).
- Điều này loại bỏ nhu cầu về các điều kiện
if-else
lồng nhau trong lớpOrder
.
- Cải tiến: Mỗi chiến lược giảm giá hiện đóng gói hành vi cụ thể của nó, làm cho nó có thể tái sử dụng và dễ mở rộng.
2. Tạo các lớp chiến lược cho Loại đơn hàng
- Tính toán phụ phí cho
delivery
,dine-in
vàtakeout
được chuyển sang các lớp chiến lược riêng của chúng (ví dụ:DeliveryOrder
,DineInOrder
).
- Các lớp này xử lý logic dựa trên vị trí (ví dụ: phí giao hàng nội thành hoặc ngoại thành) mà không làm lộn xộn lớp
Order
chính.
- Cải tiến: Việc thêm một loại đơn hàng mới, như "CateringOrder", chỉ yêu cầu tạo một lớp chiến lược mới mà không cần sửa đổi mã hiện có.
3. Đơn giản hóa lớp Order
chính
- Lớp
Order
hiện đóng vai trò là người điều phối nhẹ:- Nó ủy quyền tính toán giảm giá cho một
DiscountStrategy
.
- Nó ủy quyền tính toán phụ phí cho một
OrderTypeStrategy
.
- Nó xử lý tính toán thuế dựa trên kết quả của các chiến lược này.
- Nó ủy quyền tính toán giảm giá cho một
- Cải tiến: Lớp
Order
hiện nay sạch sẽ, tập trung và tuân thủ Nguyên tắc Trách nhiệm Đơn nhất.
4. Sử dụng Thành phần hơn là Kế thừa
- Thay vì mã hóa logic kinh doanh vào một lớp duy nhất, việc tái cấu trúc sử dụng thành phần, kết hợp các chiến lược một cách động.
- Cải tiến: Điều này làm cho hệ thống linh hoạt và dễ tùy chỉnh hơn cho các kịch bản khác nhau.
Mã đã được tái cấu trúc
class DiscountStrategy:
"""Lớp cơ sở cho các chiến lược giảm giá."""
def apply_discount(self, order):
return order.base_price
class VIPDiscount(DiscountStrategy):
def apply_discount(self, order):
return order.base_price * 0.9 # Giảm giá 10% cho VIP
class FirstTimeDiscount(DiscountStrategy):
def apply_discount(self, order):
return order.base_price * 0.85 # Giảm giá 15% cho khách hàng lần đầu
class NoDiscount(DiscountStrategy):
def apply_discount(self, order):
return order.base_price
class OrderTypeStrategy:
"""Lớp cơ sở cho các chiến lược loại đơn hàng."""
def apply_surcharge(self, order):
return 0
class DeliveryOrder(OrderTypeStrategy):
def apply_surcharge(self, order):
return 5 if order.location == "urban" else 10 # Phí giao hàng dựa trên vị trí
class DineInOrder(OrderTypeStrategy):
def apply_surcharge(self, order):
return 2 # Phí phục vụ cho các đơn hàng ăn tại chỗ
class TakeoutOrder(OrderTypeStrategy):
def apply_surcharge(self, order):
return 0 # Không phụ phí cho mang đi
class Order:
def __init__(self, base_price, discount_strategy, order_type_strategy, location=None):
self.base_price = base_price
self.discount_strategy = discount_strategy
self.order_type_strategy = order_type_strategy
self.location = location
def calculate_total(self):
# Ủy quyền tính toán giảm giá và phụ phí
discounted_price = self.discount_strategy.apply_discount(self)
surcharge = self.order_type_strategy.apply_surcharge(self)
# Logic thuế
tax_rate = 0.05 if self.location in ["urban", "rural"] else 0.02
tax = discounted_price * tax_rate
# Tính toán tổng
return discounted_price + surcharge + tax
4. Tại sao nó tốt hơn
Mã đã được tái cấu trúc cung cấp một số lợi thế:
- Tính khả đọc: Mỗi trách nhiệm được xác định rõ ràng trong lớp của nó.
- Khả năng mở rộng: Việc thêm các giảm giá hoặc loại đơn hàng mới rất dễ dàng—chỉ cần tạo các lớp mới.
- Khả năng kiểm thử: Các chiến lược riêng lẻ có thể được kiểm thử độc lập.
- Khả năng bảo trì: Thay đổi một phần của logic sẽ không ảnh hưởng đến các phần khác.
5. Kết luận
Bằng cách tái cấu trúc hệ thống đặt món nhà hàng, chúng ta đã biến một khối if-else lồng nhau lộn xộn thành một thiết kế hướng đối tượng mô đun. Cách tiếp cận này đảm bảo mã sạch sẽ, có thể mở rộng và dễ bảo trì hơn.
Nếu hệ thống của bạn đang bị nhấn chìm trong sự phức tạp, hãy xem xét áp dụng các nguyên tắc thiết kế tương tự để đơn giản hóa và bảo vệ nó trong tương lai!