大家好,我是大华。 最近在公司做了一个小项目,是关于订单处理的。一开始我们团队是这么写的:
java
public class OrderService {
public void createOrder(String type) {
if ("normal".equals(type)) {
// 普通订单逻辑
System.out.println("创建普通订单");
} else if ("vip".equals(type)) {
// VIP订单逻辑
System.out.println("创建VIP订单,优先处理");
} else if ("group".equals(type)) {
// 团购订单逻辑
System.out.println("创建团购订单,检查人数");
}
// ...后面还可能加更多类型
}
}
看起来没问题吧?但问题很快就来了:
- 新增一种订单类型,就得改这个类,违反了开闭原则(对扩展开放,对修改关闭)。
- 逻辑全堆在一个方法里,越来越难读。
- 每种订单的处理流程其实差不多:校验 → 创建 → 发通知 → 记日志,只是每一步的具体实现不一样。
这时候,我们老大说:该用抽象类了。
什么时候必须用抽象类?
说必须可能有点绝对,但下面几种情况,用抽象类会特别合适:
- 有一堆相似的东西,它们有共同的流程,但每个细节不一样。
- 你想强制子类必须实现某些方法,不然就不让用。
- 你不想让别人直接
new
一个概念性的类,比如动物、订单这种。
我们这个订单系统就符合第一条。
怎么用?一步步改
第一步:先搞一个抽象类,把流程定下来。
java
// 抽象类:订单处理器
public abstract class OrderProcessor {
// 模板方法:定义整个流程
public final void process() {
validate();
create();
notifyUser();
log();
}
// 校验(每种订单都得校验,但方式不同)
protected abstract void validate();
// 创建订单(具体实现由子类决定)
protected abstract void create();
// 通知用户(可以有默认行为)
protected void notifyUser() {
System.out.println("发送通用通知");
}
// 记日志(所有订单都一样)
private void log() {
System.out.println("订单已记录到日志");
}
}
注意几个点:
abstract class
:表示这个类不能被直接 new。abstract void validate()
和create()
:这两个方法没有 body,子类必须实现。process()
是 final 的,防止子类修改流程。notifyUser()
有默认实现,子类可以覆盖,也可以不覆盖。
第二步:写具体的订单处理器
比如 VIP 订单:
java
public class VipOrderProcessor extends OrderProcessor {
@Override
protected void validate() {
System.out.println("校验VIP资格和余额");
}
@Override
protected void create() {
System.out.println("创建VIP订单,标记优先级");
}
@Override
protected void notifyUser() {
System.out.println("发送VIP专属通知");
}
}
再比如团购订单:
java
public class GroupOrderProcessor extends OrderProcessor {
@Override
protected void validate() {
System.out.println("检查团购人数是否达标");
}
@Override
protected void create() {
System.out.println("创建团购订单,设置倒计时");
}
}
第三步:使用它们
java
// 根据订单类型,选择对应的处理器
OrderProcessor processor;
if ("vip".equals(type)) {
processor = new VipOrderProcessor();
} else if ("group".equals(type)) {
processor = new GroupOrderProcessor();
} else {
processor = new NormalOrderProcessor(); // 普通订单
}
// 调用统一流程
processor.process();
这样做的好处
- 流程统一 :不管什么订单,都是
process()
一步到位。 - 扩展方便:加新订单类型?写个新类继承就行,不用动老代码。
- 强制规范 :你继承我,就必须实现
validate
和create
,不然编译都过不了。 - 减少重复:公共逻辑(比如记日志)写在抽象类里,子类不用重复。
再举个生活化的例子
想象你在做"做早餐"App。
- 做煎蛋:打蛋 → 煎 → 装盘
- 做三明治:切面包 → 加料 → 烤 → 装盘
你会发现,装盘是共有的,但前面步骤不同。
这时候你就可以写个抽象类BreakfastMaker
:
java
abstract class BreakfastMaker {
public final void make() {
prepare();
cook();
pack(); // 装盘是统一的
}
protected abstract void prepare();
protected abstract void cook();
protected void pack() {
System.out.println("装盘完成");
}
}
然后让EggMaker
和SandwichMaker
去继承它。
总结一下
抽象类不是什么高级技巧,而是为了解决实际问题。
当你发现一堆类做类似的事,流程差不多,但细节不同。你想让子类必须实现某些方法,那就可以考虑用抽象类+抽象方法。