抽象父类应提取子类真正共有的本质特征与基础行为,通过对比字段含义、方法逻辑及流程固定性来识别共性;合理使用protected成员、具体方法、抽象方法和模板方法;避开语义不同、public字段、未初始化属性等误区;确保构造约束、子类专注差异逻辑、新增子类无需修改父类且支持类型归一化。

抽象父类提取公共属性和方法,核心是识别子类之间真正共有的、稳定不变的“本质特征”和“基础行为”,而不是简单堆砌字段或复制粘贴代码。
从子类中识别共性内容
先列出多个具体子类(如 Apple、Banana、Orange),逐个对比:
- 哪些字段在所有子类中都存在且含义一致?比如 name、weight、harvestDate
- 哪些方法逻辑高度相似,仅细节不同?比如 getPrice() 都要算单价×重量,但单价来源不同
- 哪些操作流程固定,只是某几步由子类决定?比如 process() 总是包含校验→处理→记录,只有“处理”需子类实现
把共性内容合理放进抽象父类
不是所有共用字段都适合放进来,要按用途区分:
-
protected 成员变量:供子类直接复用,如
protected final String id;、protected BigDecimal basePrice; -
具体方法:完整实现、可被子类直接调用,如
public void logCreation() { System.out.println("Created: " + this.id); } -
抽象方法:只声明不实现,强制子类提供差异逻辑,如
public abstract BigDecimal calculateTax(); -
模板方法:用具体方法封装流程骨架,调用抽象方法留出扩展点,如
public final void sell() { validate(); BigDecimal total = basePrice.multiply(weight); total = calculateTax().add(total); recordSale(total); }
避开常见误区
避免把“看起来一样”但语义或生命周期不同的东西硬塞进抽象类:
- 不放子类专属字段(如 Apple 的
variety、Banana 的ripenessLevel) - 不声明
public字段——破坏封装,子类随意修改可能让模板方法失效 - 不空着必填属性(如
protected String code;不初始化),应在构造器中强制传入 - 不为兼容旧代码而保留冗余方法,抽象类要精简、意图清晰
验证是否提取得当
一个好用的抽象父类,应满足:
- 子类实例化时,必须提供所有关键信息(通过构造参数约束)
- 子类只需专注自己独有的那部分逻辑,其余由父类托底
- 新增子类时,不需修改抽象类就能接入统一流程
- 用
isinstance(obj, AbstractFruit)(Python)或obj instanceof Fruit(Java)能自然归一化处理

















