抽象实体应立足业务本质,从需求中提取稳定、有身份的名词作为实体,用枚举、值对象封装业务语义,构造时强制合法状态,使实体成为业务规则第一道防线。

在业务场景中抽象实体,关键不是先写代码,而是回到业务本身——看清“谁在做什么、拥有什么、受什么约束”。类不是技术容器,而是对真实业务角色或资源的精准建模。抽象得准,后续扩展才不卡壳;抽象偏了,加个字段都要改三层。
从真实业务动词和名词里找实体
打开需求文档或和产品聊一次,圈出所有带“的”“能”“有”“需”字眼的表达:
- “用户能提交订单” → “订单”是实体,“提交”是它的行为(方法)
- “商品有库存、有价格、属于某个分类” → “商品”“库存”“分类”都可能是独立实体,而非全塞进一个类
- “优惠券有过期时间、有限定使用条件” → 时间和条件不是简单属性,可能需要封装成
ValidityPeriod或UsageRule子对象
避免把“操作”当实体(比如“下单服务”“支付动作”),它们属于Service层职责;实体必须是业务中稳定存在、有身份、可被追踪的东西(如订单号唯一、用户ID不可变)。
用“能不能独立存在”判断是否拆分
一个类该不该包含某个字段,看它是否违背“单一职责”:
- 订单类里放
String deliveryAddress可以,但放String logisticsCompany+String trackingNumber+Date estimatedArrival就超载了——这些属于“物流信息”,应抽成DeliveryInfo类,订单只持有一个deliveryInfo引用 - 用户类里放
String phone合理,但若要支持短信验证、语音验证、邮箱验证多种方式,就不该只用一个字符串,而应建ContactMethod抽象类,让SmsContactEmailContact继承
拆分后,实体之间是“has-a”关系(订单有物流信息),不是“is-a”(订单是物流信息)——后者才用继承。
属性设计要反映业务语义,不是数据库字段
别直接照搬表结构。例如数据库有个status字段存数字0/1/2,业务上它实际代表“待支付/已发货/已完成”。这时实体类应该:
- 用枚举
OrderStatus替代int status,值为PENDINGSHIPPEDCOMPLETED - 在setter里校验状态流转合法性(比如不能从“已完成”倒退到“待支付”)
- 提供
canCancel()isDeliverable()这类业务方法,而不是暴露原始状态值让调用方自己if-else
再比如“金额”不写double amount,而用BigDecimal amount并配currency字段——因为业务中“100元”和“100美元”语义完全不同,不能混算。
构造方法要守住业务入口关
实体对象一旦创建,就应处于合法、可用状态。别留一堆空参构造+全设setter的“半成品”:
- 订单必须有用户ID、商品列表、创建时间 → 这些放进有参构造,强制传入
- 某些字段允许为空(如发票抬头),就用Builder模式或提供明确命名的静态工厂方法:
Order.createWithoutInvoice(userId, items) - 在构造中做轻量级校验:用户ID非空、商品列表非空、时间不为null——错误留在创建时,不蔓延到后续逻辑
无参构造仅保留给框架反序列化(如MyBatis、Jackson),且应设为protected,避免业务代码随意new出无效对象。
不复杂但容易忽略:实体类不是数据搬运工,它是业务规则的第一道防线。每次加字段前,先问一句——这个值,是不是这个实体天然就该“拥有”或“决定”的?
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











