Java中枚举类型的妙用

在我们开发企业级应用中,有时候会有这样的需求,需要定义一些常量,比如数字1 代表一个含义,数字2代表一个含义。

为了方便讲解,我们这里假设需要定义订单状态。

订单状态 1.待付款 10.待发货 20 已发货 30 待评价 40已完成 -10:已取消

在这种情况下,对于初级程序员可能就会这样定义

// 订单类型 1 待付款
public static final Integer WAIT_PAY=1;
// 订单类型 10 待发货
public static final Integer WAIT_SEND_GOODS=10;
//订单类型 20 已发货
public static final Integer HAVE_SEND_GOODS=20;
//订单类型 30 待评价
public static final Integer WAIT_COMMENT=30;
//订单类型 40 已完成
public static final Integer HAVE_FINISH=40;
//订单类型 -10 取消订单
public static final Integer CANCEL_ORDER=-10;

这里每一个数字代表一个订单状态,这样设计虽然也能满足需求,但是会存在一些问题:

  • 如果开发没有很好的注释,那么可能开发一段时间后你自己就忘了订单状态的含义
  • 如果今后项目交接后,接收你项目的人找不到充足的注释那么很难理解每个状态的含义。
  • 如果今后增加了新的订单状态,但是注释没有更新,那么新人接手很可能会出现问题。

那么有没有什么更好的解决方法呢?

答案是肯定的,那就是使用Java中的枚举类型。

import lombok.Getter;
/**
 * 商城订单状态
 * @author qing-feng.zhao
 */
public enum OrderStatusEnum {
    /**
     * 订单状态 1.待付款 10.待发货 20 已发货 30 待评价 40已完成  -10:已取消
     */
    WAIT_PAY(1,"待付款"),
    WAIT_SEND_GOODS(10,"待发货"),
    HAVE_SEND_GOODS(20,"已发货"),
    WAIT_COMMENT(30,"待评价"),
    HAVE_FINISH(40,"已完成"),
    HAVE_CANCEL(-10,"已取消");

    @Getter
    private Integer key;
    @Getter
    private String display_name;

    OrderStatusEnum(Integer key, String display_name) {
        this.key = key;
        this.display_name = display_name;
    }
}

配置好后,如果我们想在业务逻辑中使用就可以这样调用:

OrderStatusEnum.WAIT_PAY.name(); // 输出结果: WAIT_PAY
OrderStatusEnum.WAIT_PAY.getKey();  //输出结果:1
OrderStatusEnum.WAIT_PAY.getDisplay_name());  //输出结果:待付款
OrderStatusEnum.WAIT_PAY.ordinal();//输出结果: 0
OrderStatusEnum.WAIT_SEND_GOODS.ordinal();//输出结果 1
OrderStatusEnum.HAVE_SEND_GOODS.ordinal();//输出结果 2
OrderStatusEnum.WAIT_COMMENT.ordinal();//输出结果 3
OrderStatusEnum.HAVE_FINISH.ordinal();//输出结果 4
OrderStatusEnum.HAVE_REFUND_PAY.ordinal();//输出结果 5

或者这样进行赋值

        String orderStatusDisplayName;
        Integer orderStatus=1;
        switch (orderStatus)
        {
            case 1:
                orderStatusDisplayName=OrderStatusEnum.WAIT_PAY.getDisplay_name();
                break;
            case 10:
                orderStatusDisplayName=OrderStatusEnum.WAIT_SEND_GOODS.getDisplay_name();
                break;
            case 20:
                orderStatusDisplayName=OrderStatusEnum.HAVE_SEND_GOODS.getDisplay_name();
                break;
            case 30:
                orderStatusDisplayName=OrderStatusEnum.WAIT_COMMENT.getDisplay_name();
                break;
            case 40:
                orderStatusDisplayName=OrderStatusEnum.HAVE_FINISH.getDisplay_name();
                break;
            case -10:
                orderStatusDisplayName=OrderStatusEnum.HAVE_CANCEL.getDisplay_name();
                break;
            default:
                orderStatusDisplayName="未知的订单状态";
                break;
        }
        log.info("输出订单状态标签:{}",orderStatusDisplayName);//输出结果:输出订单状态标签:待付款

这样写的话,有一个好处就是当每个数字代表的含义发生变化,

比如“待评价”要改成“已收货”或新增订单状态类型的时候,就不需要在程序中到处去找,去修改,只需修改枚举类中的配置即可。

但是以上其实还存在一个问题,那就是订单状态数字如果还是写死的,那么是不完美的。

其实我们完全还可以针对上面的程序在做一个优化。

        String orderStatusDisplayName=null;
        Integer orderStatus=1;
        for (OrderStatusEnum item:OrderStatusEnum.values()) {
            if(item.getKey().equals(orderStatus)){
                orderStatusDisplayName=item.getDisplay_name();
            }
        }
        log.info("输出订单状态标签:{}",orderStatusDisplayName);// 输出结果: 输出订单状态标签 待付款

经过上面的学习,聪明的你会发现,我们使用了OrderStatusEnum.values()的方法,遍历了所有的枚举类型。

然后在循环中做了判断,大大简化并优化了代码的编写和维护。

到这里,基本上枚举类型的基础用法就讲完了。

不过,博主打算再分享一个系统设计方法。

我们前面提到

订单状态 1.待付款 10.待发货 20 已发货 30 待评价 40已完成 -10:已取消

如果我们想直接返回订单状态列表(包括订单状态数字和显示标签),不需要做判断,那么应该怎么做呢?

这时候其实我们可以这样,先封装一个所有枚举类型通用的VO类——EnumDicVO。

import lombok.Data;

import java.io.Serializable;

/**
 * @author qing-feng.zhao
 */
@Data
public class EnumDicVO implements Serializable {
    private Integer key;
    private String display_name;
}

然后遍历所有的枚举类型,并封装一个获取所有枚举类型code和标签的静态方法即可。

     public static List<EnumDicVO> findAllEnumList() {
        if(null==OrderStatusEnum.values()||OrderStatusEnum.values().length<=0){
            return Collections.EMPTY_LIST;
        }
        List<EnumDicVO> orderStatusList=new ArrayList<>(OrderStatusEnum.values().length);
        EnumDicVO enumDicVO;
        for (OrderStatusEnum item:OrderStatusEnum.values()
        ) {
            enumDicVO =new EnumDicVO();
            enumDicVO.setKey(item.getKey());
            enumDicVO.setDisplay_name(item.getDisplay_name());
            orderStatusList.add(enumDicVO);
        }
        return orderStatusList;
    }

最后由于这个方法可能会在很多地方都会调用,因此我们直接封装到枚举类中。

最终优化版本如下:

import lombok.Getter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 商城订单状态
 * @author qing-feng.zhao
 */
public enum OrderStatusEnum {
    /**
     * 这里是静态成员变量而不是实例化成员属性
     * 订单状态 1.待付款 10.待发货 20 已发货 30 待评价 40已完成  -10:已取消
     */
    WAIT_PAY(1,"待付款"),
    WAIT_SEND_GOODS(10,"待发货"),
    HAVE_SEND_GOODS(20,"已发货"),
    WAIT_COMMENT(30,"待评价"),
    HAVE_FINISH(40,"已完成"),
    HAVE_CANCEL(-10,"已取消");
    
    //静态方法
    public static List<EnumDicVO> findAllEnumList() {
        if(null==OrderStatusEnum.values()||OrderStatusEnum.values().length<=0){
            return Collections.EMPTY_LIST;
        }
        List<EnumDicVO> orderStatusList=new ArrayList<>(OrderStatusEnum.values().length);
        EnumDicVO enumDicVO;
        for (OrderStatusEnum item:OrderStatusEnum.values()
        ) {
            enumDicVO =new EnumDicVO();
            enumDicVO.setKey(item.getKey());
            enumDicVO.setDisplay_name(item.getDisplay_name());
            orderStatusList.add(enumDicVO);
        }
        return orderStatusList;
    }

    //实例化成员属性
    @Getter
    private Integer key;
    @Getter
    private String display_name;

    //实例化构造方法
    OrderStatusEnum(Integer key, String display_name) {
        this.key = key;
        this.display_name = display_name;
    }
}

值得注意的是,

  • WAIT_PAY 是静态值对象,并不是实例化成员属性值
  • 如果不是很理解的话可以看下这篇反编译详解:重新认识java(十) ---- Enum(枚举类)
  • 我们这里findAllEnumList()方法中其实是静态方法中调用了实例化构造方法。
  • 上面如果不好理解的话,我们可以换个例子
import java.util.ArrayList; import java.util.List; 
/**  
* @author qing-feng.zhao  
*/ 
public class CommonEnum {
    private static MyPageParam MyPageA=new MyPageParam(1,10);
    private static MyPageParam MyPageB=new MyPageParam(2,20);

    public static List<MyPageParam> findAllEnumList() {
        List<MyPageParam> myList=new ArrayList<>();
        myList.add(MyPageA);
        myList.add(MyPageB);
        return myList;
    }
} 

这样我们无论在哪里想要获取这个枚举类型列表都可以这样调用就行了:

List<EnumDicVO> orderStatusList=TimerTaskTypeEnum.findAllEnumList();
log.info("{}",orderStatusList);

输出结果:

[EnumDicVO(key=1, display_name=待付款), EnumDicVO(key=10, display_name=待发货), EnumDicVO(key=20, display_name=已发货), EnumDicVO(key=30, display_name=待评价), EnumDicVO(key=40, display_name=已完成), EnumDicVO(key=-10, display_name=已取消)]

UI最终 效果
在这里插入图片描述
本篇完~

感谢您的阅读,喜欢我的文章,欢迎点赞关注或分享。

技术宅星云 CSDN认证博客专家 Java Spring MySQL
技术宅星云(网名),英文名fairy,CSDN博客专家,先后曾在外企惠普,央企中航信工作, 目前担任北京蛙跳科技有限公司后端高级开发工程师,负责公司短视频应用后台,擅长JAVA后端技术.
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页
实付 59.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值