当前位置: 首页 > news >正文

枚举实战

Java 枚举的 3 个实战场景:从状态码到策略模式

枚举不只是"定义常量",用好了能让代码干净一半。

适合人群:刚学完 Enum 语法、想知道"实际项目中怎么用"的同学。
阅读时间:约 8 分钟。


目录

  • 场景 1:状态 / 类型定义(最常用)
  • 场景 2:策略模式(替换大量 if/else)
  • 场景 3:统一返回码(后端接口必备)
  • 完整可运行代码
  • 总结

场景 1:状态 / 类型定义(最常用)

问题:魔法数字与魔法字符串

// 烂代码示例
if (order.getStatus() == 1) {// 待支付
} else if (order.getStatus() == 2) {// 已支付
}
// 1 和 2 是什么意思?新同事一脸懵,数据库里也是裸数字

枚举重构

文件:OrderStatus.java

public enum OrderStatus {PENDING_PAYMENT("待支付", 1),PAID("已支付", 2),SHIPPED("已发货", 3),COMPLETED("已完成", 4),CANCELLED("已取消", 5);private final String desc;private final int code;OrderStatus(String desc, int code) {this.desc = desc;this.code = code;}public String getDesc() { return desc; }public int getCode() { return code; }// 根据 code 反查枚举(数据库里存的是 code)public static OrderStatus of(int code) {for (OrderStatus status : values()) {if (status.code == code) return status;}throw new IllegalArgumentException("未知状态码: " + code);}
}

文件:OrderStatusDemo.java

public class OrderStatusDemo {public static void main(String[] args) {// 1. 基本使用OrderStatus status = OrderStatus.PAID;System.out.println("当前状态: " + status.getDesc());System.out.println("状态码: " + status.getCode());// 2. 遍历所有状态(适合展示枚举的规范性)System.out.println("\n=== 所有订单状态 ===");for (OrderStatus s : OrderStatus.values()) {System.out.printf("code=%d, desc=%s%n", s.getCode(), s.getDesc());}// 3. 根据 code 反查(数据库场景)OrderStatus fromDb = OrderStatus.of(3);System.out.println("\n从数据库 code=3 反查: " + fromDb);}
}

运行截图

image

对比

维度 魔法数字 枚举
可读性 需要查文档或注释 自描述
类型安全 任意 int 都能传 编译期检查
维护性 改一个值要全局搜索 改枚举定义一处即可
数据库映射 手动维护 通过 getCode() / of() 统一映射

场景 2:策略模式(替换大量 if/else)

问题:臃肿的分支判断

public BigDecimal calculatePrice(String role, BigDecimal amount) {if ("VIP".equals(role)) {return amount.multiply(new BigDecimal("0.9"));} else if ("SVIP".equals(role)) {return amount.multiply(new BigDecimal("0.75"));} else if ("NORMAL".equals(role)) {return amount;}// 每新增一个角色,就要改这里,违反开闭原则throw new IllegalArgumentException("未知角色: " + role);
}

痛点:新增角色要改核心方法,容易出错,且逻辑和配置混在一起。

枚举策略重构

文件:DiscountStrategy.java

import java.math.BigDecimal;public enum DiscountStrategy {NORMAL("普通会员") {@Overridepublic BigDecimal apply(BigDecimal amount) {return amount; // 无折扣}},VIP("VIP会员") {@Overridepublic BigDecimal apply(BigDecimal amount) {return amount.multiply(new BigDecimal("0.9")); // 9折}},SVIP("SVIP会员") {@Overridepublic BigDecimal apply(BigDecimal amount) {return amount.multiply(new BigDecimal("0.75")); // 75折}};private final String roleName;DiscountStrategy(String roleName) {this.roleName = roleName;}public abstract BigDecimal apply(BigDecimal amount);public String getRoleName() {return roleName;}
}

文件:StrategyDemo.java

import java.math.BigDecimal;public class StrategyDemo {public static void main(String[] args) {BigDecimal amount = new BigDecimal("1000");System.out.println("=== 不同角色折扣计算 ===");for (DiscountStrategy strategy : DiscountStrategy.values()) {BigDecimal finalPrice = strategy.apply(amount);System.out.printf("%s: 原价 %s → 实付 %s%n", strategy.getRoleName(), amount, finalPrice);}}
}

运行截图

image

对比

维度 if/else 版本 枚举策略版本
新增角色 修改核心类 新增枚举常量即可
单元测试 测一个长方法 每个策略独立测试
可读性 逻辑堆在一起 策略自描述
扩展性 违反开闭原则 符合开闭原则

如果策略逻辑很复杂,也可以在枚举里只存一个 Supplier<Strategy> 或函数接口,把具体实现类延迟加载。


场景 3:统一返回码(后端接口必备)

问题:错误码散落各处

// Controller A
return new Result(500, "服务器内部错误", null);// Controller B
return new Result(500, "系统错误", null);
// 同样的 500,消息不一样,前端无法统一处理

枚举统一封装

文件:ResultCode.java

public enum ResultCode {SUCCESS(200, "操作成功"),BAD_REQUEST(400, "请求参数错误"),UNAUTHORIZED(401, "未登录或 token 过期"),FORBIDDEN(403, "无权限访问"),NOT_FOUND(404, "资源不存在"),INTERNAL_ERROR(500, "服务器内部错误"),SERVICE_BUSY(503, "服务繁忙,请稍后重试");private final int code;private final String message;ResultCode(int code, String message) {this.code = code;this.message = message;}public int getCode() { return code; }public String getMessage() { return message; }// 统一包装成 Result 对象public <T> Result<T> toResult() {return new Result<>(this.code, this.message, null);}public <T> Result<T> toResult(T data) {return new Result<>(this.code, this.message, data);}
}

文件:Result.java

public class Result<T> {private int code;private String message;private T data;public Result(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}// 快速成功public static <T> Result<T> ok(T data) {return ResultCode.SUCCESS.toResult(data);}// 快速失败public static <T> Result<T> error(ResultCode resultCode) {return resultCode.toResult();}public int getCode() { return code; }public String getMessage() { return message; }public T getData() { return data; }
}

文件:ResultCodeDemo.java

public class ResultCodeDemo {public static void main(String[] args) {// 模拟成功响应Result<String> success = Result.ok("用户数据");System.out.println("成功响应:");System.out.println("  code: " + success.getCode());System.out.println("  message: " + success.getMessage());System.out.println("  data: " + success.getData());System.out.println();// 模拟失败响应Result<String> error = Result.error(ResultCode.NOT_FOUND);System.out.println("失败响应:");System.out.println("  code: " + error.getCode());System.out.println("  message: " + error.getMessage());System.out.println("  data: " + error.getData());}
}

运行截图

image

对比

维度 硬编码返回 枚举统一返回
语义一致性 各处写法可能不同 一处定义,全局复用
维护成本 改消息要全局搜索 改枚举一处即可
国际化 难以扩展 可在枚举里扩展 getMessage(Locale)
前端协作 错误码语义不清 前后端按枚举约定对接

完整可运行代码

把以下 7 个文件放在同一个包(或同一个文件夹)下:

文件名 类型 说明
OrderStatus.java enum 场景 1 枚举定义
OrderStatusDemo.java class 场景 1 运行入口(右键运行)
DiscountStrategy.java enum 场景 2 枚举定义
StrategyDemo.java class 场景 2 运行入口(右键运行)
ResultCode.java enum 场景 3 枚举定义
Result.java class 场景 3 泛型包装类
ResultCodeDemo.java class 场景 3 运行入口(右键运行)

注意:只有带 main 方法的 *Demo.java 才能直接运行,枚举文件本身没有 main 方法,无法直接运行。

总结

三个场景速查表

场景 判断标准 核心收益
状态/类型定义 一组固定值,且需要附带描述或码值 类型安全、可读性强、数据库映射方便
策略模式 多分支逻辑,且分支可能新增 消灭 if/else,符合开闭原则
统一返回码 前后端协作,需要集中管理错误语义 错误码标准化,降低维护成本

如果对你有帮助,欢迎点赞和收藏。有任何问题或更好的实践,欢迎在评论区交流。

http://www.jsqmd.com/news/970755/

相关文章:

  • 合肥瓷砖批发 TOP5 评测|本地瓷砖仓库怎么选?2026 年高性价比采购指南 - 行业深度观察C
  • 从Tushare迁移到AKShare v1.1.1:手把手教你用Python缓存股票历史数据,提速20分钟
  • Day4 细化细节,规避学习漏洞
  • 2026年 真空热压炉/热压烧结炉/材料热压炉厂家推荐榜:高精度温控与核心烧结技术实力深度解析 - 品牌发掘
  • Honey Select 2终极汉化补丁:3步告别日语困扰,畅享中文游戏体验
  • 抖音内容批量下载技术解析:从数据采集到智能管理的完整解决方案
  • 凤城母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • 垂直领域小模型蒸馏:最佳实践指南
  • Shizuku v13.6.0深度技术解析:Android系统API直接调用的架构革新
  • 2026上海防水补漏服务商口碑测评榜单|全屋渗漏维修机构优选指南(6月最新) - 宅安选房屋修缮
  • 四川钢管供应商公司|无缝钢管|焊管|镀锌管|螺旋焊管|方矩管 - 四川盛世钢联营销中心
  • 2026年6月热门的不锈钢管供货商推荐,不锈钢无缝管/焊管/大口径不锈钢焊管/无缝管,不锈钢管优质厂家推荐分析 - 品牌推荐师
  • RoboMaster竞赛用ROS2自瞄系统包:含装甲板YOLO检测、卡尔曼轨迹预测与完整部署配置
  • 从实验室到生产环境:手把手教你规划VMware vSphere 7.0的授权策略(附各版本功能对比)
  • 2026年深圳短视频运营公司盘点:推荐16年老品牌深圳昊客网络 - 猫头鹰AI推广
  • 温州 GEO 优化实战指南:核心逻辑拆解 + 避坑指南 + 八家本地服务商全面测评 - 玖叁鹿
  • 敦煌母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • GraphRAG vs 无向量RAG vs 向量RAG(2026年高级上下文工程指南)
  • 市面上有哪些是真正性价比高的AI智能降重工具(告别论文AI标记风险)
  • 事件分析:FDE标准,“OpenClaw+RAG+Agent” 应用实战的标准
  • 宠乐圈互助平台
  • 保姆级教程:用QGIS 3.28切好瓦片,再用Nginx发布,Cesium调用一步到位
  • 终极Discord消息清理指南:如何一键删除数千条聊天记录
  • 如何彻底移除Windows Defender?5步终极指南释放系统性能
  • 如何用Python在3分钟内批量下载无水印抖音视频?这个开源工具让你轻松搞定!
  • 东港母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • 四川钢板供应商公司|热轧板|中厚板|热轧卷|花纹板|高强钢板 - 四川盛世钢联营销中心
  • 2026年GEO源码部署公司权威评测:避坑与选型指南 - 品牌报告
  • QMCDecode:3步解锁QQ音乐加密文件,实现跨平台播放自由
  • 从依赖报错到跑通Demo:Ubuntu 20.04下VSCode配置OpenCV C++的完整避坑实录