类与对象设计的关键在于准确反映问题域、职责清晰、易于维护。应区分实体对象(如order、user)与控制对象(如orderservice),遵循单一职责原则,通过封装保护状态,优先组合而非继承,并控制继承层级不超过两层。

类与对象的设计是否合理,关键不在于写得“多”或“炫”,而在于能不能准确反映问题域、便于理解、易于修改和扩展。核心是让类成为真实职责的清晰载体,让对象成为可预期、可协作的实体。
明确区分实体对象与控制对象
不是所有类都该承担相同角色。现实建模中要分清两类基本对象:
-
实体对象:代表问题域里的具体事物,有自身状态和内在行为。比如
Order(订单)、User(用户)、Payment(支付)。它们的属性(如status、balance)和方法(如cancel()、charge())应紧密围绕自身生命周期展开,不越界处理外部流程。 -
控制对象:不拥有核心业务数据,专责协调多个实体完成某项任务。比如
OrderService(处理下单全流程)、RefundProcessor(执行退款策略)。这类对象通常不含持久状态,方法多为组合调用,参数和返回值清晰表达意图。
混用这两类角色——例如在 User 类里直接写发邮件、调库存、生成报表的逻辑——会导致类膨胀、职责模糊、难以测试。
遵循单一职责,一个类只解决一个问题
判断标准很简单:当需求变动时,如果一个修改需要同时改三处不同功能的代码,那大概率这个类已经超载了。
- 把数据验证、数据库操作、API序列化全塞进一个
Product类?不合理。验证逻辑可抽成ProductValidator,持久化交给ProductRepository,序列化由ProductSerializer负责。 - 一个
ReportGenerator类既查数据库、又做统计、又导出 Excel?应拆为DataFetcher、Calculator、Exporter,再由顶层协调者组装。
职责越单一,类越稳定;越稳定,复用和单元测试就越容易落地。
用封装保护状态,暴露最小必要接口
类不是“数据容器+一堆函数”的集合。它的价值在于对内管控、对外契约清晰。
- 属性尽量设为私有(Python 中用
_name或__name约定),通过 getter/setter 或专用方法控制访问。比如set_discount_rate()可校验范围、触发日志、通知监听器,而直接赋值obj._rate = -5就绕过了全部保障。 - 避免提供“万能 setter”:不要写
update_field(name, value)这类泛化接口。每个可变状态的变更路径应当明确、可追溯、可拦截。 - 构造函数应完成必要初始化,拒绝创建出“半成品”对象。比如
Order(status='draft')合理,Order()创建出 status 为None的实例就埋下隐患。
优先组合,谨慎继承
继承不是为了“复用代码”,而是为了表达“是一种”的严格语义关系。滥用会快速破坏可维护性。
- 别因为
Dog和Cat都有name就拉个Animal出来继承——除非你真需要在运行时统一处理所有动物行为(如zoo.feed_all_animals())。 - 更通用的做法是:用协议(Protocol)或抽象基类定义行为契约(如
CanBark、CanMeow),再让具体类实现;或通过组合委托能力,比如Dog持有一个BarkingBehavior实例,需要时调用.bark()。 - 继承层级建议不超过两层。三层以上往往意味着设计在强行拟合,而不是自然浮现。











