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


Tái cấu trúc Python - Trường hợp thực tế: Hệ thống đặt món nhà hàng
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 làm cho 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 tình huống 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 địa điểm.
Đây là triển khai ban đầu lộn xộn:
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
làm cho mã khó đọc và theo dõi.
- Logic được phân tán khắp phương thức, làm cho việc hiểu mã đang làm gì chỉ bằng cái nhìn thoáng qua trở nên khó khă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 được 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 duy 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 trong một phần 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à địa điểm.
- 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à địa điểm.
-
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ã có liên quan.
- Nguy cơ xảy ra lỗi trong quá trình thay đổi như vậy là rất 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ã có liên quan.
-
Kết hợp chặt chẽ:
- Tất cả logic kinh doanh được kết hợp 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 hợp 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 tách logic thành các lớp có thể sử dụng lại, tuân theo các nguyên tắc chính như tính mô-đun, đóng gói và tách biệt các mối quan tâm.
Những cải tiến chính trong việc 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ỏ sự cần thiết của các điều kiện
if-else
lồng nhau bên trong lớpOrder
.
- Cải tiến: Mỗi chiến lược giảm giá giờ đây đóng gói hành vi cụ thể của nó, làm cho nó có thể sử dụng lại và dễ mở rộng.
2. Tạo các lớp chiến lược cho các loại đơn hàng
- Các phép tính 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
cốt lõi
- Lớp
Order
hiện đóng vai trò là người phối hợp 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
giờ đây sạch sẽ, tập trung và tuân thủ Nguyên tắc trách nhiệm duy nhất.
4. Sử dụng soạn thảo thay vì kế thừa
- Thay vì mã hóa cứng logic kinh doanh vào một lớp duy nhất, việc tái cấu trúc sử dụng soạn thảo, 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 trường hợp 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 địa điểm
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ế:
- Khả năng đọ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 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 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 có 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ó cho tương lai!