别再问了!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. 强制规范 :你继承我,就必须实现validatecreate,不然编译都过不了。
  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("装盘完成");
    }
}

然后让EggMakerSandwichMaker去继承它。

总结一下

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

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

相关推荐
艾醒几秒前
大模型面试题剖析:大模型微调与训练硬件成本计算
人工智能·后端·算法
Dioass1 分钟前
Java面向对象中你大概率会踩的五大隐形陷阱
java
自由生长20244 分钟前
每日知识-设计模式-状态机模式
后端
用户298698530149 分钟前
如何使用 Spire.Doc 在 C# 中创建、写入和读取 Word 文档?
后端
一叶飘零_sweeeet14 分钟前
在分布式环境下正确使用MyBatis二级缓存
java·分布式·mybatis
林太白34 分钟前
项目中的层级模块到底如何做接口
前端·后端·node.js
肥仔哥哥193039 分钟前
基于OpenCv做照片分析(Java)
java·人工智能·opencv·图像原理
一枚小小程序员哈40 分钟前
基于Android的车位预售预租APP/基于Android的车位租赁系统APP/基于Android的车位管理系统APP
android·spring boot·后端·struts·spring·java-ee·maven
没有bug.的程序员43 分钟前
JVM 学习与提升路线总结:从入门到精通的系统化指南
java·jvm·学习·提升
用户30742971671581 小时前
Spring AI实战:基于ElevenLabs 实现文本转语音的实时音频流
java·spring boot·ai编程