作为从业十余年的老码农,我见过太多"能跑就行"的代码最终演变成难以维护的"屎山"。今天,我想通过一个电商订单处理系统的重构案例,分享如何将混乱的代码转化为优雅的设计。这个案例来自我去年主导的一个真实项目重构,过程中踩过的坑和收获的经验,或许能给你带来启发。
我们接手的是一个Python实现的电商订单处理模块,核心功能包括:
原始代码把所有逻辑塞进了一个长达80行的process_order函数,典型的"上帝对象"反模式。让我们看看这段代码的主要问题:
python复制def process_order(data):
d = json.loads(data)
user = d['user']
items = d['items']
total = 0
for i in items:
total += i['price'] * i['quantity']
# 应用折扣(长达20行的if-elif链)
if user['vip'] == 1:
total = total * 0.9
elif user['vip'] == 2:
total = total * 0.8
# ...更多折扣逻辑
# 检查库存
for i in items:
stock = get_stock(i['id'])
if stock < i['quantity']:
return "FAIL"
# 扣减库存、支付、通知等更多逻辑...
提示:在实际审查代码时,我习惯用Checklist逐项检查这些"坏味道"。建议团队可以建立自己的代码质量检查表。
我们采用小步快跑的重构策略:
原始代码使用字典表示所有业务概念,这导致类型不安全且意图模糊。我们引入数据类:
python复制from dataclasses import dataclass
from typing import List
@dataclass
class Item:
id: str
price: float
quantity: int
@dataclass
class User:
id: int
vip_level: int = 0
balance: float = 0.0
email: str = None
phone: str = None
coupon: str = None
@dataclass
class Order:
user: User
items: List[Item]
promotion: str = None
重构收益:
原始代码用长串if-elif处理折扣,违反开闭原则。我们引入策略模式:
python复制from abc import ABC, abstractmethod
class DiscountStrategy(ABC):
@abstractmethod
def apply(self, order: Order) -> float:
pass
class VipDiscount(DiscountStrategy):
def apply(self, order: Order) -> float:
if order.user.vip_level == 1:
return 0.9
elif order.user.vip_level == 2:
return 0.8
return 1.0
class CouponDiscount(DiscountStrategy):
def apply(self, order: Order) -> float:
if order.user.coupon == "SUMMER":
return 50 # 固定减免
elif order.user.coupon == "WINTER":
return 0.85 # 折扣率
return 0
使用方式:
python复制def calculate_total(order: Order, strategies: List[DiscountStrategy]) -> float:
subtotal = sum(item.price * item.quantity for item in order.items)
for strategy in strategies:
discount = strategy.apply(order)
if isinstance(discount, float): # 折扣率
subtotal *= discount
else: # 固定金额
subtotal -= discount
return subtotal
经验分享:
原始代码直接依赖具体实现,难以测试。我们抽象服务接口:
python复制class InventoryService(ABC):
@abstractmethod
def check_stock(self, item_id: str, quantity: int) -> bool:
pass
@abstractmethod
def reduce_stock(self, item_id: str, quantity: int) -> None:
pass
class PaymentService(ABC):
@abstractmethod
def charge(self, user: User, amount: float) -> bool:
pass
class NotificationService(ABC):
@abstractmethod
def notify(self, user: User, message: str) -> None:
pass
重构后的OrderProcessor:
python复制class OrderProcessor:
def __init__(
self,
inventory: InventoryService,
payment: PaymentService,
notifier: NotificationService,
discount_strategies: List[DiscountStrategy]
):
self.inventory = inventory
self.payment = payment
self.notifier = notifier
self.strategies = discount_strategies
def process(self, order: Order) -> None:
# 使用注入的服务处理订单
total = self._calculate_total(order)
if not self._check_inventory(order.items):
raise InsufficientStockError()
self._reduce_inventory(order.items)
if not self.payment.charge(order.user, total):
raise PaymentFailedError()
self.notifier.notify(
order.user,
f"订单支付成功,金额:{total}"
)
实操建议:
code复制┌─────────────────┐ ┌─────────────────┐
│ OrderProcessor │──────▶│ InventoryService │
└─────────────────┘ └─────────────────┘
▲ ▲
│ │
│ │
┌─────────────────┐ ┌─────────────────┐
│ DiscountStrategy │ │ PaymentService │
└─────────────────┘ └─────────────────┘
▲ ▲
│ │
│ │
┌─────────────────┐ ┌─────────────────┐
│ NotificationServ │ │ Logger │
└─────────────────┘ └─────────────────┘
可测试性:每个组件都可以独立测试
python复制def test_order_processor():
mock_inventory = Mock(InventoryService)
mock_payment = Mock(PaymentService)
processor = OrderProcessor(mock_inventory, mock_payment, ...)
# 测试各种场景
可扩展性:新增支付方式只需实现PaymentService
python复制class CreditCardPayment(PaymentService):
def charge(self, user: User, amount: float) -> bool:
# 调用支付网关API
return True
可维护性:修改折扣逻辑只需调整对应策略类
过度设计陷阱:
事务一致性难题:
python复制def process_order(self, order: Order):
try:
self.inventory.reserve(order.items) # 预留库存
self.payment.charge(order.user, total) # 扣款
self.inventory.commit(order.items) # 确认预留
except Exception as e:
self.inventory.cancel_reservation(order.items) # 取消预留
raise
性能考量:
python复制def check_and_reduce_inventory(self, items: List[Item]) -> bool:
for item in items:
if not self.inventory.check(item.id, item.quantity):
return False
self.inventory.reduce(item.id, item.quantity)
return True
静态分析:
测试工具:
重构辅助:
对称性:
节奏感:
留白:
隐喻:
个人体会:重构不仅是技术活动,更是一种心性修炼。每次重构都是与代码对话的过程,需要耐心、专注和对美的追求。