zoukankan      html  css  js  c++  java
  • (9)枚举通用接口&枚举使用规范

    1. 数据表里字段值为有穷序列的字段,对应到程序里特定的枚举。字段数据类型尽量用varchar取代int(或tinyint)。毋庸置疑,字母组合总比0、1、2、3这样的数字易于识别。

    2. 数据表字段如果有对应的枚举,则,在字段注释上要标明枚举类名,方便程序溯源。

    3. 枚举一般有两部分,一个是枚举项值,一个是枚举描述。那么,这两个属性怎么命名呢? code和desc?还是value和desc?还是key和value?本文重点针对这个问题阐述。

    为什么要用枚举? 有穷序列的字段用int或tinyint不是挺好吗?

    答案很简单:我们的程序写给人看的。

    既然是写给人看,那么,可理解、易理解往往显得相当重要!

    我曾经认识的一位架构师强调过:对于企业应用系统,当前的硬件资源和技术条件已经很给力了,通常情况下,我们大可不必为了追求性能而将类型、状态等字段定义成数字类型;而编写易理解、可维护的系统,已经越发显得重要了。将这些字段定义成字符串类型,用字符串来描述字段值,就是易理解的一个重要体现。

    深谙其理。深有体会。

    而且,我也一直在这么践行。

    关于枚举的好处,我曾连篇赘述->/tag/枚举/。本文继续。

    随着项目的不断开发迭代,大家在项目里定义的枚举越来越多。这些枚举类的结构很相同,不同之处仅仅是各枚举项。另外,在对枚举的使用方面也五花八门,毕竟每个人对技术的理解和认知甚至工作态度是不同的,而且,程序运行过程中偶尔还会有NPE找上门来。

    @Getter
    @AllArgsConstructor
    public enum LevelEnum {
    
        FIRST("FIRST", "一级"),
        SECOND("SECOND", "二级"),
        THIRD("THIRD", "三级");
    
    
        private String code;
        private String value;
    
        public static LevelEnum getBeanByCode(String code) {
            LevelEnum[] statusEnums = LevelEnum.values();
            for (LevelEnum v : statusEnums) {
                if (v.getCode().equals(code)) {
                    return v;
                }
            }
            return null;
        }
    }
    @Getter
    @AllArgsConstructor
    public enum OrderStatusEnum {
    
        INIT("INIT", "初始"),
        ACCOUNTING("ACCOUNTING", "记账中"),
        SUCCESS("SUCCESS", "付款成功"),
        FAILED("FAILED", "付款失败");
    
    
        private String key;
        private String description;
    
        public static OrderStatusEnum getBeanByCode(String code) {
            OrderStatusEnum[] values = OrderStatusEnum.values();
            for (OrderStatusEnum v : values) {
                if (v.getKey().equals(code)) {
                    return v;
                }
            }
            return null;
        }
    }
     
    @AllArgsConstructor
    public enum ProductEnum {
        BOSSKG("BOSS开工"),
        HUICHUXING("惠出行"),
        SICHEBANGONG("私车办公"),
        YOUFU("优付"),
        UNKNOWN("未知"),
        ;
        
        private String description;
    
        private String getCode(){
            return this.toString();
        }
    
        public String getDescription() {
            return description;
        }
        
        public static ProductEnum getBean(String value) {
            ProductEnum[] values = ProductEnum.values();
            for(ProductEnum temp : values){
                if(temp.getCode().equals(value)){
                    return temp;
                }
            }
            return ProductEnum.UNKNOWN;
        }
    }
     
    @Getter
    @AllArgsConstructor
    public enum SeasonEnum {
        SPRING(1, "春"),
        SUMMER(2, "夏"),
        AUTUMN(3, "秋"),
        WINTER(4, "冬");
        private int code;
        private String description;
        
        public static SeasonEnum getBeanByCode(Integer code) {
            if (null == code) return null;
            SeasonEnum[] values = SeasonEnum.values();
            for (SeasonEnum temp : values) {
                if (temp.getCode() == code) {
                    return temp;
                }
            }
            return null;
        }
    }

    秉承着老司机的职业素养,我站在团队开发规范的角度上思考,能否为这些枚举定义统一的接口,这样,大家在使用的时候就更统一了。下面interface是我和组内一个优秀的小伙伴的成果,它界定了枚举的通用操作:

    /**
     * 如若枚举名称和实际值不同,请务必重写getKey方法
     * 枚举定义规范:枚举名切记大写,描述尽量清晰,不要出现错误拼写,请自觉仔细检查
     * 例如:
     * MONDAY("星期一"),
     * TUESDAY("星期二")
     *
     * @author shaozhengmao
     * @create 2021-06-21 10:18 上午
     */
    public interface EnumAbility<T> {
    
        /**
         * 返回枚举实际值
         * @return
         */
        T getCode();
    
        /**
         * 返回枚举描述
         *
         * @return 枚举说明
         */
        String getDescription();
    
        /**
         * 对比当前枚举对象和传入的枚举值是否一致(String类型会忽略大小写)
         * 当前枚举项是否匹配远端传入的值(比如:数据库的字段值、rpc传入的参数值)
         *
         * @param enumCode 枚举code
         * @return 是否匹配
         */
        default boolean codeEquals(T enumCode) {
            if (enumCode == null) return false;
            if (enumCode instanceof String) {
                return ((String) enumCode).equalsIgnoreCase((String) getCode());
            } else {
                return Objects.equals(this.getCode(), enumCode);
            }
        }
    
        /**
         * 对比两个枚举项是否完全相同(==)
         *
         * @param anotherEnum 枚举
         * @return 是否相同
         */
        default boolean equals(EnumAbility<T> anotherEnum) {
            return this == anotherEnum;
        }
    }

    同时,还定义了一个工具方法,用来根据code来获取对应的枚举项:

    这样,上面示例中的枚举将简化为:

    @Getter
    @AllArgsConstructor
    public enum LevelEnum implements EnumAbility<String> {
    
        FIRST("FIRST", "一级"),
        SECOND("SECOND", "二级"),
        THIRD("THIRD", "三级");
    
    
        private String code;
        private String value;
    
        @Override
        public String getDescription() {
            return value;
        }
    
        /**
         * 2021-12-18 23:00 zhanggz:本方法存在歧义,请使用{@link #getDescription()}
         * @return
         */
        @Deprecated
        public String getValue() {
            return value;
        }
    
        public static LevelEnum getBeanByCode(String code) {
            return (LevelEnum) EnumAbilityUtil.getEnumByCode(LevelEnum.class, code);
        }
    }
    @Getter
    @AllArgsConstructor
    public enum OrderStatusEnum implements EnumAbility<String> {
    
        INIT("INIT", "初始"),
        ACCOUNTING("ACCOUNTING", "记账中"),
        SUCCESS("SUCCESS", "付款成功"),
        FAILED("FAILED", "付款失败");
    
    
        private String key;
        private String description;
        
    
        @Override
        public String getCode() {
            return key;
        }
        
        /**
         * 2021-12-18 23:00 zhanggz:本方法存在歧义,请使用{@link #getCode()}
         * @return
         */
        @Deprecated
        public String getKey() {
            return key;
        }
    
        public static OrderStatusEnum getBeanByCode(String code) {
            return (OrderStatusEnum) EnumAbilityUtil.getEnumByCode(OrderStatusEnum.class, code);
        }
    }
     
    @AllArgsConstructor
    public enum ProductEnum implements EnumAbility<String> {
        BOSSKG("BOSS开工"),
        HUICHUXING("惠出行"),
        SICHEBANGONG("私车办公"),
        YOUFU("优付"),
        UNKNOWN("未知"),
        ;
        
        private String description;
    
        @Override
        private String getCode(){
            return this.toString();
        }
    
        @Override
        public String getDescription() {
            return description;
        }
        
        public static ProductEnum getBean(String code) {
            return (ProductEnum) EnumAbilityUtil.getEnumByCode(ProductEnum.class, code);
        }
    }
     
    @Getter
    @AllArgsConstructor
    public enum SeasonEnum implements EnumAbility<Integer> {
        SPRING(1, "春"),
        SUMMER(2, "夏"),
        AUTUMN(3, "秋"),
        WINTER(4, "冬");
        private Integer code;
        private String description;
    
        public static SeasonEnum getBeanByCode(Integer code) {
            if (null == code) return null;
            return (SeasonEnum) EnumAbilityUtil.getEnumByCode(SeasonEnum.class, code);
        }
    }
  • 相关阅读:
    符号解析
    编译器与链接器的功能
    hook的本质就是在本原可执行文件中加东西
    Mac-O文件加载的全过程(一)
    系统在执行可执行文件几个过程
    动态库连接器–动态库链接信息(Mach-O文件格式和程序从加载到执行过程)
    load 调用的顺序
    iPhone Mach-O文件格式与代码签名
    Redis正确使用的十个技巧
    redis slowlog
  • 原文地址:https://www.cnblogs.com/buguge/p/15706392.html
Copyright © 2011-2022 走看看