应提取真正共有且语义一致的属性和方法,避免为复用而破坏职责边界;优先用接口处理部分共性行为,抽象基类配合模板方法封装固定流程与可变步骤,属性须私有并提供受控的getter/setter。

在 Java 中设计基类提取公共属性和方法,核心是识别多个子类间真正共有的、语义一致的数据和行为,并通过继承合理组织。关键不是“能抽就抽”,而是“该抽才抽”——避免为了复用而破坏类的职责边界或引入不必要的耦合。
明确“公共性”:只提取稳定、通用、语义一致的内容
公共属性和方法必须满足三个条件:所有子类都确实需要、含义完全相同、未来变更倾向一致。例如,User 和 Product 都有 id 和 createdAt,但它们的 id 类型(Long vs String)、生成逻辑(雪花ID vs UUID)、业务含义(用户标识 vs 商品编码)可能不同,此时强行抽取到同一基类反而增加理解成本和维护风险。
更合理的做法是:
- 若多个实体都需审计字段(如 createdBy、updatedAt),且由同一框架(如 Spring Data JPA)统一处理,可提取为 AuditableEntity
- 若只有部分子类需某个方法(如“计算折扣”仅适用于 Order 和 Coupon),优先考虑接口(Discountable)而非基类
- 避免抽取“看似通用”的字段如 status 或 remark,除非所有子类对它的取值范围、状态流转、校验规则完全一致
使用抽象基类 + 模板方法,控制扩展点
当公共流程固定、但某些步骤因子类而异时,适合用抽象基类配合模板方法模式。基类定义骨架,子类实现差异部分。
例如订单处理流程:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 基类 OrderProcessor 定义 process() 模板方法:校验 → 锁库存 → 创建支付单 → 发送通知
- 将 validate()、lockInventory() 声明为 protected abstract,由子类(NormalOrderProcessor、GroupBuyOrderProcessor)各自实现
- 公共逻辑(如日志记录、事务管理)统一写在基类中,避免重复
属性设计:优先封装,谨慎暴露 protected 字段
基类中的公共属性应尽量设为 private,提供 protected 的 getter/setter,而非直接 protected 字段。这既支持子类访问,又保留未来加校验、日志、懒加载等扩展能力。
例如:
// ✅ 推荐:封装 + 可控访问
public abstract class BaseEntity {
private Long id;
private LocalDateTime createdAt;
protected void setId(Long id) {
if (id == null || id
<p>避免:</p>
<pre class="brush:java;toolbar:false;">// ❌ 不推荐:裸露字段破坏封装
protected Long id;
protected LocalDateTime createdAt;
方法设计:区分 final、abstract 和 default 实现
根据方法意图选择修饰符:
- final 方法:基类已确定不可变的核心逻辑(如统一的日志格式化)
- abstract 方法:子类必须提供差异化实现(如“计算运费”规则各不相同)
- 带默认实现的 protected 方法:提供可选复用能力(如 generateTraceId()),子类可直接用,也可重写
- 避免在基类中放业务强相关的 public 方法(如 sendEmail()),这类行为更适合由服务层协调,而非绑定到领域对象
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










