面试题答案
一键面试import logging
from functools import wraps
# 库存检查装饰器
def check_stock(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
if self.stock < 1:
raise Exception("商品库存不足")
return func(self, *args, **kwargs)
return wrapper
# 操作日志记录装饰器
def log_operation(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
result = func(self, *args, **kwargs)
logging.info(f"记录商品 {self.name} 的 {func.__name__} 操作到数据库")
return result
return wrapper
# 价格变动通知装饰器
def notify_subscribers(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
old_price = self.price
result = func(self, *args, **kwargs)
if self.price != old_price:
logging.info(f"通知订阅者商品 {self.name} 的价格变动")
return result
return wrapper
class Product:
def __init__(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
@check_stock
@log_operation
def purchase(self):
self.stock -= 1
return f"成功购买 {self.name}"
@log_operation
@notify_subscribers
def change_price(self, new_price):
self.price = new_price
return f"成功更改 {self.name} 的价格为 {new_price}"
为确保它们在复杂业务流程中的稳定性和可维护性:
- 单一职责原则:每个装饰器只负责一项具体的功能,如库存检查、日志记录、价格变动通知,这样使得装饰器的功能明确,易于理解和维护。
- 清晰的接口和文档:为每个装饰器和被装饰的方法添加清晰的文档注释,说明其功能、参数、返回值等,方便其他开发人员理解和使用。
- 错误处理:在装饰器内部进行适当的错误处理,如库存不足时抛出有意义的异常,这样可以在调用栈的上层捕获并处理异常,确保系统的稳定性。
- 测试:为每个装饰器编写单元测试,验证其功能的正确性,特别是在不同输入和边界条件下的行为。对于组合使用的装饰器,也要编写集成测试,确保它们协同工作时的正确性。
- 可组合性:由于装饰器采用了标准的函数装饰器形式,因此可以方便地根据业务需求进行不同的组合,提高代码的灵活性和复用性。