Java枚举模块案例如何规范

wen java案例 29

本文目录导读:

Java枚举模块案例如何规范

  1. 基础枚举规范
  2. 高级枚举模式
  3. 枚举与数据库映射
  4. 枚举工具类
  5. 枚举验证与转换
  6. 最佳实践总结
  7. 常见陷阱与注意事项
  8. 项目结构建议

我来详细介绍Java枚举模块的规范案例和最佳实践。

基础枚举规范

1 命名规范

/**
 * 状态枚举 - 名词或形容词命名
 */
public enum OrderStatus {
    PENDING,      // 待处理
    PROCESSING,   // 处理中
    COMPLETED,    // 已完成
    CANCELLED     // 已取消
}
/**
 * 类型枚举 - 名词命名
 */
public enum UserType {
    ADMIN,
    NORMAL_USER,
    VIP_USER
}

2 带字段的枚举规范

/**
 * 状态码枚举 - 包含状态码和描述
 */
public enum ResponseCode {
    SUCCESS(200, "成功"),
    BAD_REQUEST(400, "请求参数错误"),
    UNAUTHORIZED(401, "未授权"),
    NOT_FOUND(404, "资源不存在"),
    INTERNAL_ERROR(500, "服务器内部错误");
    private final int code;
    private final String message;
    // 私有构造器
    ResponseCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
    // Getter方法
    public int getCode() {
        return code;
    }
    public String getMessage() {
        return message;
    }
}

高级枚举模式

1 带抽象方法的枚举

/**
 * 操作类型枚举 - 每个枚举常量有不同的行为
 */
public enum OperationType {
    ADD("+") {
        @Override
        public double apply(double a, double b) {
            return a + b;
        }
    },
    SUBTRACT("-") {
        @Override
        public double apply(double a, double b) {
            return a - b;
        }
    },
    MULTIPLY("*") {
        @Override
        public double apply(double a, double b) {
            return a * b;
        }
    },
    DIVIDE("/") {
        @Override
        public double apply(double a, double b) {
            if (b == 0) {
                throw new ArithmeticException("除数不能为0");
            }
            return a / b;
        }
    };
    private final String symbol;
    OperationType(String symbol) {
        this.symbol = symbol;
    }
    public String getSymbol() {
        return symbol;
    }
    // 抽象方法
    public abstract double apply(double a, double b);
}
// 使用示例
public class Calculator {
    public static double calculate(double a, OperationType op, double b) {
        return op.apply(a, b);
    }
}

2 策略模式枚举

/**
 * 支付策略枚举 - 不同支付方式的不同逻辑
 */
public enum PaymentStrategy {
    ALIPAY {
        @Override
        public PaymentResult pay(PaymentRequest request) {
            // 支付宝支付逻辑
            System.out.println("使用支付宝支付:" + request.getAmount());
            return new PaymentResult(true, "支付宝支付成功");
        }
    },
    WECHAT_PAY {
        @Override
        public PaymentResult pay(PaymentRequest request) {
            // 微信支付逻辑
            System.out.println("使用微信支付:" + request.getAmount());
            return new PaymentResult(true, "微信支付成功");
        }
    },
    BANK_CARD {
        @Override
        public PaymentResult pay(PaymentRequest request) {
            // 银行卡支付逻辑
            System.out.println("使用银行卡支付:" + request.getAmount());
            return new PaymentResult(true, "银行卡支付成功");
        }
    };
    public abstract PaymentResult pay(PaymentRequest request);
}
// 支付请求类
class PaymentRequest {
    private double amount;
    private String orderId;
    // getter/setter
    public double getAmount() {
        return amount;
    }
    public void setAmount(double amount) {
        this.amount = amount;
    }
    public String getOrderId() {
        return orderId;
    }
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}
// 支付结果类
class PaymentResult {
    private boolean success;
    private String message;
    public PaymentResult(boolean success, String message) {
        this.success = success;
        this.message = message;
    }
    // getter/setter
    public boolean isSuccess() {
        return success;
    }
    public String getMessage() {
        return message;
    }
}
// 使用示例
public class PaymentService {
    public PaymentResult processPayment(PaymentRequest request, PaymentStrategy strategy) {
        return strategy.pay(request);
    }
}

枚举与数据库映射

1 MyBatis枚举映射

/**
 * 性别枚举 - 数据库存储int值
 */
public enum Gender {
    MALE(1, "男"),
    FEMALE(2, "女"),
    UNKNOWN(3, "未知");
    private final int code;
    private final String displayName;
    Gender(int code, String displayName) {
        this.code = code;
        this.displayName = displayName;
    }
    // 根据code获取枚举
    public static Gender fromCode(int code) {
        for (Gender gender : Gender.values()) {
            if (gender.code == code) {
                return gender;
            }
        }
        throw new IllegalArgumentException("无效的性别代码: " + code);
    }
    public int getCode() {
        return code;
    }
    public String getDisplayName() {
        return displayName;
    }
}
// MyBatis TypeHandler
public class GenderTypeHandler extends BaseTypeHandler<Gender> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, 
                                   Gender parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, parameter.getCode());
    }
    @Override
    public Gender getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int code = rs.getInt(columnName);
        return Gender.fromCode(code);
    }
    @Override
    public Gender getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int code = rs.getInt(columnIndex);
        return Gender.fromCode(code);
    }
    @Override
    public Gender getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int code = cs.getInt(columnIndex);
        return Gender.fromCode(code);
    }
}

2 JPA枚举映射

/**
 * 订单状态枚举 - JPA映射
 */
public enum OrderStatus {
    @JsonProperty("pending")
    PENDING(0, "待支付"),
    @JsonProperty("paid")
    PAID(1, "已支付"),
    @JsonProperty("shipping")
    SHIPPING(2, "配送中"),
    @JsonProperty("completed")
    COMPLETED(3, "已完成"),
    @JsonProperty("cancelled")
    CANCELLED(4, "已取消");
    private final int code;
    private final String description;
    OrderStatus(int code, String description) {
        this.code = code;
        this.description = description;
    }
}
// JPA实体中使用
@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Enumerated(EnumType.STRING)  // 存储字符串值
    private OrderStatus status;
    // 或者使用数字存储
    @Column(name = "status_code")
    @Convert(converter = OrderStatusConverter.class)
    private OrderStatus enumStatus;
}
// 自定义转换器
@Converter
public class OrderStatusConverter implements AttributeConverter<OrderStatus, Integer> {
    @Override
    public Integer convertToDatabaseColumn(OrderStatus attribute) {
        return attribute.getCode();
    }
    @Override
    public OrderStatus convertToEntityAttribute(Integer dbData) {
        return OrderStatus.fromCode(dbData);
    }
}

枚举工具类

/**
 * 枚举工具类 - 提供通用的枚举操作方法
 */
public final class EnumUtils {
    // 私有构造器,防止实例化
    private EnumUtils() {
        throw new UnsupportedOperationException("工具类不能被实例化");
    }
    /**
     * 根据字段值查找枚举
     * @param enumClass 枚举类
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @param <T> 枚举类型
     * @param <V> 字段类型
     * @return 枚举实例,未找到返回null
     */
    public static <T extends Enum<T>, V> T fromField(Class<T> enumClass, 
                                                     String fieldName, 
                                                     V fieldValue) {
        try {
            for (T enumConstant : enumClass.getEnumConstants()) {
                Field field = enumClass.getDeclaredField(fieldName);
                field.setAccessible(true);
                Object value = field.get(enumConstant);
                if (value.equals(fieldValue)) {
                    return enumConstant;
                }
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("查询枚举失败", e);
        }
        return null;
    }
    /**
     * 判断是否包含某个枚举值
     */
    public static <T extends Enum<T>> boolean contains(Class<T> enumClass, String value) {
        try {
            Enum.valueOf(enumClass, value);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
    /**
     * 获取枚举的可选值列表(用于下拉菜单等)
     */
    public static <T extends Enum<T>> List<Map<String, Object>> getOptions(Class<T> enumClass) {
        List<Map<String, Object>> options = new ArrayList<>();
        for (T enumConstant : enumClass.getEnumConstants()) {
            Map<String, Object> option = new HashMap<>();
            option.put("name", enumConstant.name());
            option.put("ordinal", enumConstant.ordinal());
            options.add(option);
        }
        return options;
    }
}
// 使用示例
public class EnumExample {
    public static void main(String[] args) {
        // 查找枚举
        OrderStatus status = EnumUtils.fromField(OrderStatus.class, 
                                                "code", 1);
        System.out.println("状态: " + status);
        // 判断枚举是否存在
        boolean exists = EnumUtils.contains(Gender.class, "MALE");
        System.out.println("性别MALE是否存在: " + exists);
        // 获取可选值
        List<Map<String, Object>> options = EnumUtils.getOptions(Gender.class);
        System.out.println("可选值: " + options);
    }
}

枚举验证与转换

1 Jackson枚举序列化/反序列化

/**
 * 枚举序列化/反序列化配置
 */
public class EnumConfig {
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer enumCustomizer() {
        return builder -> {
            // 全局枚举反序列化配置
            builder.deserializerByType(Enum.class, new JsonDeserializer<Enum>() {
                @Override
                public Enum deserialize(JsonParser p, DeserializationContext ctxt) 
                        throws IOException {
                    String value = p.getText();
                    // 获取当前字段的枚举类型
                    Class<?> enumClass = p.getCurrentValue().getClass();
                    // 根据名称查找
                    return (Enum) Enum.valueOf((Class<Enum>) enumClass, value.toUpperCase());
                }
            });
        };
    }
}
// 自定义枚举序列化器
public class EnumSerializer extends JsonSerializer<Enum<?>> {
    @Override
    public void serialize(Enum<?> value, JsonGenerator gen, 
                         SerializerProvider serializers) throws IOException {
        gen.writeString(value.name());
    }
}
// 自定义枚举反序列化器
public class EnumDeserializer extends JsonDeserializer<Enum<?>> {
    @Override
    public Enum<?> deserialize(JsonParser p, DeserializationContext ctxt) 
            throws IOException {
        String value = p.getText();
        // 根据实际枚举类型处理
        if (p.getCurrentValue() instanceof OrderStatus) {
            return OrderStatus.valueOf(value.toUpperCase());
        }
        return null;
    }
}

2 Bean Validation枚举验证

/**
 * 枚举验证注解
 */
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValidator.class)
public @interface ValidEnum {
    String message() default "无效的枚举值";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    Class<? extends Enum<?>> enumClass();
    boolean ignoreCase() default false;
}
// 验证器实现
public class EnumValidator implements ConstraintValidator<ValidEnum, String> {
    private Class<? extends Enum<?>> enumClass;
    private boolean ignoreCase;
    @Override
    public void initialize(ValidEnum annotation) {
        this.enumClass = annotation.enumClass();
        this.ignoreCase = annotation.ignoreCase();
    }
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null || value.isEmpty()) {
            return true; // 空值验证由@NotNull处理
        }
        for (Enum<?> enumConstant : enumClass.getEnumConstants()) {
            if (ignoreCase) {
                if (enumConstant.name().equalsIgnoreCase(value)) {
                    return true;
                }
            } else {
                if (enumConstant.name().equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }
}
// 使用示例
public class UserDTO {
    @ValidEnum(enumClass = Gender.class, ignoreCase = true)
    private String gender;
    @NotNull
    @ValidEnum(enumClass = UserType.class)
    private String userType;
    // getter/setter
}

最佳实践总结

1 设计原则

  1. 单一职责:一个枚举只表示一组相关的常量
  2. 不可变性:枚举字段使用final修饰
  3. 完整性:提供完整的常量和必要的静态方法

2 性能优化

/**
 * 枚举缓存优化 - 避免频繁遍历
 */
public enum StatusEnum {
    ACTIVE(1, "启用"),
    INACTIVE(2, "禁用"),
    DELETED(3, "删除");
    private final int code;
    private final String description;
    // 缓存所有枚举
    private static final Map<Integer, StatusEnum> CACHE = new HashMap<>();
    static {
        for (StatusEnum status : StatusEnum.values()) {
            CACHE.put(status.code, status);
        }
    }
    StatusEnum(int code, String description) {
        this.code = code;
        this.description = description;
    }
    // 高效查找
    public static StatusEnum fromCode(int code) {
        StatusEnum status = CACHE.get(code);
        if (status == null) {
            throw new IllegalArgumentException("无效的状态代码: " + code);
        }
        return status;
    }
    // Getter
    public int getCode() {
        return code;
    }
    public String getDescription() {
        return description;
    }
}

3 文档规范

/**
 * 用户状态枚举
 * 
 * <p>用于表示用户在系统中的各种状态</p>
 * 
 * <ul>
 *   <li>ACTIVE - 正常使用中</li>
 *   <li>INACTIVE - 已停用</li>
 *   <li>FROZEN - 已冻结(例如违规)</li>
 *   <li>DELETED - 已删除</li>
 * </ul>
 * 
 * @author xxx
 * @since 1.0.0
 */
public enum UserStatus {
    /** 正常 */
    ACTIVE,
    /** 停用 */
    INACTIVE,
    /** 冻结 */
    FROZEN,
    /** 删除 */
    DELETED
}

常见陷阱与注意事项

/**
 * 枚举注意事项示例
 */
public enum WarningExample {
    // 正确:构造器必须私有
    INSTANCE(1) {
        @Override
        public void doSomething() {
            // 正确:匿名内部类
        }
    };
    private final int value;
    // 正确:私有构造器
    WarningExample(int value) {
        this.value = value;
    }
    // 正确:抽象方法
    public abstract void doSomething();
    // 错误示例(仅说明,实际无法编译)
    /*
    public WarningExample() {
        // 错误:枚举构造器不能是public
    }
    public enum InnerEnum {
        // 正确:枚举内可以定义枚举
    }
    */
    // 错误:不要在枚举中过度依赖ordinal()
    // ordinal()可能随枚举顺序改变而改变
    // 正确:使用自定义字段
    public int getValue() {
        return value;
    }
    // 正确:使用静态查找方法
    public static WarningExample fromValue(int value) {
        for (WarningExample example : WarningExample.values()) {
            if (example.value == value) {
                return example;
            }
        }
        throw new IllegalArgumentException("无效的值: " + value);
    }
    // 注意:switch语句中的枚举
    public String getWarningMessage() {
        switch (this) {
            case INSTANCE:
                return "这是一个实例";
            default:
                return "未知";
        }
    }
}

项目结构建议

com.example.enums/
├── common/
│   ├── BaseEnum.java           // 枚举基类接口
│   ├── EnumUtils.java          // 枚举工具类
│   └── converter/             // 类型转换器
├── order/
│   ├── OrderStatus.java       // 订单状态
│   ├── OrderType.java         // 订单类型
│   └── PaymentMethod.java     // 支付方式
├── user/
│   ├── UserStatus.java        // 用户状态
│   ├── UserType.java          // 用户类型
│   └── Gender.java           // 性别
└── system/
    ├── ResponseCode.java     // 响应码
    ├── ErrorCode.java        // 错误码
    └── OperationType.java    // 操作类型

这就是Java枚举模块的规范案例,包含了从基础到高级的各种使用场景和最佳实践,遵循这些规范可以提高代码的可读性、可维护性和可扩展性。

抱歉,评论功能暂时关闭!