别再问了!Java里这几种场景,用抽象类就对了

大家好,我是大华。 最近在公司做了一个小项目,是关于订单处理的。一开始我们团队是这么写的:

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("创建团购订单,检查人数");
        }
        // ...后面还可能加更多类型
    }
}

看起来没问题吧?但问题很快就来了:

  • 新增一种订单类型,就得改这个类,违反了开闭原则(对扩展开放,对修改关闭)。
  • 逻辑全堆在一个方法里,越来越难读。
  • 每种订单的处理流程其实差不多:校验 → 创建 → 发通知 → 记日志,只是每一步的具体实现不一样。

这时候,我们老大说:该用抽象类了。


什么时候必须用抽象类?

说必须可能有点绝对,但下面几种情况,用抽象类会特别合适:

  1. 有一堆相似的东西,它们有共同的流程,但每个细节不一样。
  2. 你想强制子类必须实现某些方法,不然就不让用。
  3. 你不想让别人直接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();

这样做的好处

  1. 流程统一 :不管什么订单,都是process()一步到位。
  2. 扩展方便:加新订单类型?写个新类继承就行,不用动老代码。
  3. 强制规范 :你继承我,就必须实现validate和create,不然编译都过不了。
  4. 减少重复:公共逻辑(比如记日志)写在抽象类里,子类不用重复。

再举个生活化的例子

想象你在做"做早餐"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去继承它。

总结一下

抽象类不是什么高级技巧,而是为了解决实际问题。

当你发现一堆类做类似的事,流程差不多,但细节不同。你想让子类必须实现某些方法,那就可以考虑用抽象类+抽象方法。

相关推荐
apcipot_rain1 小时前
C++转Java日记(06)
java·开发语言
脚本自动化开发4 小时前
柔光屏平板怎么选?华为 MatePad Air Z 柔光版学
后端
程序猿DD5 小时前
OctaFuse 2.19.0:重做管理后台界面与交互,模型目录同步更新
后端
金銀銅鐵6 小时前
带您看懂字节码指令(一):一帧里有什么
java·后端·ai编程
码事漫谈7 小时前
Agent 测评是什么?大白话讲一讲
后端
皮皮林5517 小时前
在 IDEA 里斗个地主不过分吧!
后端
nice_lcj5208 小时前
【从零理解 Spring AI · 14】RAG 的四个环节:加载、切分、向量化、检索
java·spring boot·embedding·向量数据库·rag·spring ai·ai应用开发
SomeOtherTime8 小时前
Rust所有权(AI回答)
开发语言·后端·rust
程序员cxuan9 小时前
离谱,AI 大佬顺手搓了个 YouTube ,而我顺手给他搓了个中文插件
人工智能·后端·程序员
学长毕设9 小时前
基于springboot科创竞赛信息平台-附源码
java·spring boot·后端