extends 实现的是类继承关系而非业务父子关系,本质是代码复用与类型兼容;业务中的父子关系应通过组合+外键(如 parentId)建模,而非 extends。

extends 实现的不是业务父子关系,而是类继承关系
用 extends 声明类之间的继承,本质是「代码复用 + 类型兼容」,不是建模业务中的“父订单-子订单”或“父用户-子账户”这类语义化父子。业务上所谓的“父子”,通常需要字段关联(如 parent_id)或聚合结构,和 extends 无关。
常见误解是:以为写 class OrderItem extends Order 就表示“订单项属于订单”。这反而破坏了数据建模合理性——OrderItem 和 Order 是不同实体,前者不“是”后者的一种,也不应共享其字段和行为。
什么时候该用 extends?看实际继承需求
只有满足「is-a」关系且存在可复用的共性逻辑时,才考虑 extends。例如:
- 多个支付方式(
AlipayPayment、WechatPayment)都具备process()和refund()行为,可抽象出Payment父类 - 不同状态的审批单(
DraftApproval、ApprovedApproval)共享基础字段(id、createdBy)和校验逻辑,可继承自Approval -
AdminUser和NormalUser都有login()、getProfile(),但权限逻辑差异大,适合用extends User+ 重写方法
注意:extends 不解决关联查询、级联保存、树形结构遍历等问题。这些得靠数据库外键、ORM 的 ManyToOne 映射或递归查询实现。
容易踩的坑:把继承当关联用
典型错误示例:
class ChildOrder extends Order { /* 错!ChildOrder 不是 Order 的一种 */ }
后果包括:
- 数据库表设计混乱:是单表继承?还是每类一张表?JPA/Hibernate 会生成不符合业务语义的 schema
- 序列化/JSON 输出泄漏父类字段,比如
ChildOrder对象意外带出Order的totalAmount字段,而它本不该有 - ORM 查询时无法自然表达 “查某个 Order 下的所有 ChildOrder”,因为两者在类型系统里是“同级子类”,不是“主从记录”
- 后续想加第三层(如
SubChildOrder)会迅速让继承链失控,违反开闭原则
业务父子关系该怎么做?用组合 + 外键
正确做法是:保留独立实体类,通过字段建立引用关系。例如:
class Order {
id: number;
}
<p>class OrderItem {
id: number;
orderId: number; // 明确指向父 Order
quantity: number;
}</p>
配套措施:
- 在 ORM 中配置
@ManyToOne(() => Order)(TypeORM)或belongTo('Order')(Sequelize) - 查询时显式
include: [{ model: OrderItem }]或写 JOIN SQL - 如需树形结构(如部门上下级),用
parentId: number字段 + 递归 CTE 或闭包表,而不是Department extends Department
继承和组合不是二选一,而是分工明确:继承管“行为复用”,组合管“关系建模”。混用就会让类既承担类型扩展职责,又背负业务语义,最后谁都管不好。










