电商订单系统应遵循面向对象设计原则:拆分Order、User、Product类以保证单一职责;用状态模式管控订单状态流转;通过PromotionStrategy接口实现优惠策略可插拔;隔离领域模型与数据库操作,确保可扩展性与维护性。

电商订单系统是典型的面向对象设计应用场景,核心在于用类准确建模现实业务实体及其关系,同时兼顾可扩展性与职责分离。关键不是堆砌设计模式,而是让类的边界清晰、行为合理、变化局部化。
订单、商品、用户:从现实到类的映射要克制
初学者常把“订单”设计成大而全的类,包裹用户信息、商品列表、支付状态、物流单号等全部字段和方法。这违反单一职责原则。更合理的做法是拆分:
- Order:只管订单编号、创建时间、总金额、状态(待支付/已发货/已完成)、关联的用户ID和收货地址ID;不存用户或地址对象,只持ID引用
- User:封装姓名、手机号、收货地址列表(Address对象集合),但不包含订单列表——订单查用户时通过ID反查,避免双向强依赖
- Product:仅描述商品基础属性(ID、名称、单价、库存),价格变动、促销计算应由独立的PricingService处理,而非放在Product里
状态变更必须受控,别让setStatus随意调用
订单状态流转有明确业务规则:不能从“已完成”退回到“待支付”,也不能跳过“已发货”直接到“已完成”。若用简单枚举+setter,极易破坏状态一致性。
推荐用状态模式或至少封装状态变更逻辑:
立即学习“Java免费学习笔记(深入)”;
- 定义OrderStatus枚举,含合法状态及对应流转规则(如:from=CREATED, to=PAID 允许;from=SHIPPED, to=COMPLETED 允许)
- Order提供pay()、ship()、complete()等语义化方法,内部校验当前状态是否允许执行,失败则抛出IllegalOrderStateException
- 状态变更后触发事件(如OrderPaidEvent),由监听器处理发短信、减库存等后续动作,解耦主流程
优惠策略要可插拔,别硬编码在Order里
满减、折扣券、会员折上折……促销规则频繁变化。若把所有逻辑写进Order.calculateTotal(),每次新增策略都要改Order类,违背开闭原则。
提取统一接口并注入具体实现:
- 定义PromotionStrategy接口,含apply(Order order)方法
- 实现FullReductionStrategy、CouponStrategy、VipDiscountStrategy等具体类
- Order构造时接收Strategy实例(或通过工厂获取),计算总价时委托给它:“total = baseAmount - strategy.discount(order)”
- 运行时根据订单属性(如用户等级、商品品类)动态选择策略,无需修改Order代码
数据库操作与领域模型要隔离
很多项目直接让Order类继承JPA的@Entity,加@Column注解,甚至写@OneToMany关联。这导致领域模型被持久化框架绑架,测试困难、迁移成本高。
推荐分层明确:
- Domain层:纯Java类(Order、Product等),无任何框架注解,只含业务逻辑和验证
- Infrastructure层:提供OrderRepository接口,由JPA实现类(如JpaOrderRepository)负责将Domain Order转为JPA Entity再存库
- DTO(如OrderCreateRequest)用于API入参,VO(如OrderDetailResponse)用于返回,与Domain模型严格分开
好的面向对象设计,不是追求类图多漂亮,而是当运营提出“支持拼团订单自动拆单”或“增加跨境订单关税计算”时,你只需新增1–2个类,改1处注入配置,而不是翻遍Order.java到处补if-else。


















