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

总结一下

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

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

相关推荐
shark_chili10 小时前
解密计算机心脏:CPU南北桥技术发展全解析
后端
努力的小雨10 小时前
混元开源之力:spring-ai-hunyuan 项目功能升级与实战体验
后端·github
bobz96510 小时前
calico vs cilium
后端
间彧10 小时前
Spring Boot集成Spring Security 6.x完整指南
java
绝无仅有11 小时前
面试实战总结:数据结构与算法面试常见问题解析
后端·面试·github
绝无仅有11 小时前
Docker 面试常见问题及解答
后端·面试·github
程序员爱钓鱼11 小时前
Go语言100个实战案例-项目实战篇:股票行情数据爬虫
后端·go·trae
IT_陈寒11 小时前
Redis 性能翻倍的 7 个冷门技巧,第 5 个大多数人都不知道!
前端·人工智能·后端
xiezhr11 小时前
用户只需要知道「怎么办」,不需要知道「为什么炸了」
java·api·接口设计规范
xiezhr11 小时前
接口设计18条军规:写给那些半夜被“502”叫醒的人
java·api·restful