别再问了!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去继承它。

总结一下

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

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

相关推荐
Javatutouhouduan1 分钟前
Java程序员如何深入学习JVM底层原理?
java·jvm·java面试·后端开发·java架构师·java程序员·互联网大厂
王嘉俊92510 分钟前
设计模式--享元模式:优化内存使用的轻量级设计
java·设计模式·享元模式
2301_803554521 小时前
C++联合体(Union)详解:与结构体的区别、联系与深度解析
java·c++·算法
EnCi Zheng1 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6011 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring
为什么我不是源代码1 小时前
JPA读取数据库离谱问题-No property ‘selectClassByName‘ found-Not a managed type
java·sql
Lisonseekpan2 小时前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava
我真的是大笨蛋2 小时前
Redis的String详解
java·数据库·spring boot·redis·spring·缓存
心态特好2 小时前
Jwt非对称加密的应用场景
java
敢敢J的憨憨L2 小时前
GPTL(General Purpose Timing Library)使用教程
java·服务器·前端·c++·轻量级计时工具库