438_代码重构方法论¶
一句话说明¶
重构是"不改变外部行为、改善内部结构"的过程,目标是让代码更易读、易扩展、易测试,核心是每次只做一个小改动,并保证测试通过。
核心知识点¶
白话理解¶
房子的格局不好用,重新装修但不改地基——这就是重构。代码重构不是推倒重写,而是一步一步把"房间布局"改得更合理,每改一步确保"住进去还是好的"(测试通过)。
常见重构手法(Martin Fowler 经典)¶
- 提炼函数(Extract Function):把一段逻辑提成单独函数,给它一个好名字
- 内联函数(Inline Function):太短的函数直接内联,减少跳转
- 移动函数(Move Function):函数放错了类/模块,移到合适的地方
- 以查询取代临时变量:临时变量换成方法调用,减少状态
- 引入参数对象:多个相关参数打包成一个对象
- 分解条件表达式:复杂 if-else 提成函数,提高可读性
- 以多态取代条件:大量 if-else/switch 用多态替代
经典题目与解法¶
题目1:重构一段"坏代码"——把大函数拆小¶
题意:以下函数做了太多事,请重构为多个职责单一的小函数。
# ===== 重构前(bad code)=====
def process_order(order):
# 校验
if order['amount'] <= 0:
print("金额无效")
return None
if order['customer'] == '':
print("客户名为空")
return None
# 计算折扣
if order['amount'] > 1000:
discount = 0.1
elif order['amount'] > 500:
discount = 0.05
else:
discount = 0
# 计算最终价格
final = order['amount'] * (1 - discount)
# 打印收据
print(f"客户: {order['customer']}")
print(f"原价: {order['amount']}")
print(f"折扣: {discount * 100}%")
print(f"实付: {final}")
return final
# ===== 重构后(clean code)=====
def validate_order(order) -> bool:
"""校验订单合法性"""
if order['amount'] <= 0:
print("金额无效")
return False
if not order['customer']: # 空字符串判断更Pythonic
print("客户名为空")
return False
return True
def calculate_discount(amount: float) -> float:
"""根据金额计算折扣率"""
if amount > 1000:
return 0.1 # 大额客户10%折扣
if amount > 500:
return 0.05 # 中额客户5%折扣
return 0.0 # 小额无折扣
def calculate_final_price(amount: float, discount: float) -> float:
"""计算折后价"""
return amount * (1 - discount)
def print_receipt(order: dict, discount: float, final: float):
"""打印收据"""
print(f"客户: {order['customer']}")
print(f"原价: {order['amount']}")
print(f"折扣: {discount * 100:.0f}%")
print(f"实付: {final:.2f}")
def process_order(order: dict):
"""处理订单主流程——每个步骤委托给专职函数"""
if not validate_order(order): # 校验
return None
discount = calculate_discount(order['amount']) # 计算折扣
final = calculate_final_price(order['amount'], discount) # 计算价格
print_receipt(order, discount, final) # 打印收据
return final
# 测试
order = {'customer': '张三', 'amount': 1200}
process_order(order)
重构收益:每个函数职责单一,可独立测试,更易复用和修改
题目2:用多态替代 if-else(Strategy 模式)¶
题意:根据支付方式计算手续费,目前用 if-else,随着支付方式增多代码会膨胀,请重构。
# ===== 重构前(if-else膨胀)=====
def calculate_fee(payment_type: str, amount: float) -> float:
if payment_type == 'credit_card':
return amount * 0.02 # 信用卡2%
elif payment_type == 'alipay':
return amount * 0.006 # 支付宝0.6%
elif payment_type == 'wechat':
return amount * 0.006 # 微信0.6%
elif payment_type == 'bank_transfer':
return 5.0 # 银行转账固定5元
else:
raise ValueError(f"未知支付方式: {payment_type}")
# ===== 重构后(多态替代条件)=====
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
"""支付方式抽象基类"""
@abstractmethod
def calculate_fee(self, amount: float) -> float:
pass
class CreditCard(PaymentMethod):
def calculate_fee(self, amount: float) -> float:
return amount * 0.02 # 信用卡2%手续费
class Alipay(PaymentMethod):
def calculate_fee(self, amount: float) -> float:
return amount * 0.006 # 支付宝0.6%
class WechatPay(PaymentMethod):
def calculate_fee(self, amount: float) -> float:
return amount * 0.006 # 微信支付0.6%
class BankTransfer(PaymentMethod):
def calculate_fee(self, amount: float) -> float:
return 5.0 # 银行转账固定5元
# 注册表:新增支付方式只需加一行,不改 calculate_fee 主函数
PAYMENT_REGISTRY = {
'credit_card': CreditCard(),
'alipay': Alipay(),
'wechat': WechatPay(),
'bank_transfer': BankTransfer(),
}
def calculate_fee(payment_type: str, amount: float) -> float:
"""主函数:查注册表,委托给具体实现"""
method = PAYMENT_REGISTRY.get(payment_type)
if not method:
raise ValueError(f"未知支付方式: {payment_type}")
return method.calculate_fee(amount) # 多态调用
# 测试
print(calculate_fee('credit_card', 1000)) # 20.0
print(calculate_fee('alipay', 1000)) # 6.0
时间复杂度:O(1)(字典查找)
重构收益:开闭原则——对扩展开放,对修改关闭
面试技巧¶
- 先测试再重构:没有测试保护的重构是"在走钢丝",先写测试再动代码
- 小步前进:每次重构只做一件事,改完运行测试,绿灯再下一步
- 命名是最重要的重构:好的函数名让代码自说明,减少注释需求
- 说清楚 Why:面试时不只展示 How,要解释"为什么这样改更好"
- 提示代码坏味道:长函数、重复代码、过长参数列表、散弹式修改——说出这些专业术语
速查表¶
| 坏味道 | 重构手法 | 效果 |
|---|---|---|
| 长函数 | 提炼函数 | 职责单一 |
| 大量if-else | 多态/策略模式 | 开闭原则 |
| 重复代码 | 提炼共用函数 | DRY原则 |
| 过长参数列表 | 引入参数对象 | 接口清晰 |
| 数据泥团 | 提炼类 | 高内聚 |
| 魔法数字 | 提炼常量 | 可读性 |