Skip to content

用枚举类消除多个 if-else

使用枚举类(Enum)是一种优雅的方式来替代冗长的 if-else 或 switch 语句,提高代码的可读性和可维护性。

📋 目录


🔍 问题场景

典型的 if-else 代码

在实际开发中,我们经常会遇到这样的代码:

java
public class OrderService {
    
    public void processOrder(String orderType) {
        if ("ONLINE".equals(orderType)) {
            System.out.println("处理在线订单");
            // 在线订单处理逻辑
            validateOnlinePayment();
            sendConfirmationEmail();
        } else if ("OFFLINE".equals(orderType)) {
            System.out.println("处理线下订单");
            // 线下订单处理逻辑
            validateCashPayment();
            printReceipt();
        } else if ("WHOLESALE".equals(orderType)) {
            System.out.println("处理批发订单");
            // 批发订单处理逻辑
            validateCreditLimit();
            generateInvoice();
        } else if ("RETAIL".equals(orderType)) {
            System.out.println("处理零售订单");
            // 零售订单处理逻辑
            validateStock();
            updateInventory();
        } else {
            throw new IllegalArgumentException("未知的订单类型: " + orderType);
        }
    }
}

❌ 传统方案的问题

1. 代码冗长难维护

java
// 每增加一种类型,就要添加一个 if-else 分支
if ("TYPE_A".equals(type)) {
    // 逻辑 A
} else if ("TYPE_B".equals(type)) {
    // 逻辑 B
} else if ("TYPE_C".equals(type)) {
    // 逻辑 C
}
// ... 可能有几十个分支

2. 容易出错

java
// 字符串常量容易写错
if ("ONLNIE".equals(orderType)) {  // 拼写错误!
    // ...
}

// 大小写敏感
if ("online".equals(orderType)) {  // 应该是 "ONLINE"
    // ...
}

3. 缺乏类型安全

java
// 可以传入任意字符串,编译时无法检查
processOrder("INVALID_TYPE");  // 运行时才会发现错误

4. 难以扩展

java
// 添加新类型需要修改多处代码
// 1. 添加 if-else 分支
// 2. 可能需要修改相关的常量定义
// 3. 更新文档和测试

✅ 枚举类解决方案

1. 基础枚举实现

java
/**
 * 订单类型枚举
 */
public enum OrderType {
    ONLINE("在线订单"),
    OFFLINE("线下订单"),
    WHOLESALE("批发订单"),
    RETAIL("零售订单");
    
    private final String description;
    
    OrderType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

/**
 * 使用枚举的订单服务
 */
public class OrderService {
    
    public void processOrder(OrderType orderType) {
        switch (orderType) {
            case ONLINE:
                System.out.println("处理" + orderType.getDescription());
                validateOnlinePayment();
                sendConfirmationEmail();
                break;
            case OFFLINE:
                System.out.println("处理" + orderType.getDescription());
                validateCashPayment();
                printReceipt();
                break;
            case WHOLESALE:
                System.out.println("处理" + orderType.getDescription());
                validateCreditLimit();
                generateInvoice();
                break;
            case RETAIL:
                System.out.println("处理" + orderType.getDescription());
                validateStock();
                updateInventory();
                break;
        }
    }
}

// 使用示例
OrderService service = new OrderService();
service.processOrder(OrderType.ONLINE);  // 类型安全,编译时检查

2. 枚举中封装行为(推荐)

java
/**
 * 在枚举中直接封装处理逻辑
 */
public enum OrderType {
    
    ONLINE("在线订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            validateOnlinePayment();
            sendConfirmationEmail();
        }
    },
    
    OFFLINE("线下订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            validateCashPayment();
            printReceipt();
        }
    },
    
    WHOLESALE("批发订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            validateCreditLimit();
            generateInvoice();
        }
    },
    
    RETAIL("零售订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            validateStock();
            updateInventory();
        }
    };
    
    private final String description;
    
    OrderType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
    
    /**
     * 抽象方法,每个枚举常量必须实现
     */
    public abstract void process();
    
    // 辅助方法(可以被所有枚举常量调用)
    protected void validateOnlinePayment() {
        System.out.println("验证在线支付");
    }
    
    protected void sendConfirmationEmail() {
        System.out.println("发送确认邮件");
    }
    
    protected void validateCashPayment() {
        System.out.println("验证现金支付");
    }
    
    protected void printReceipt() {
        System.out.println("打印收据");
    }
    
    protected void validateCreditLimit() {
        System.out.println("验证信用额度");
    }
    
    protected void generateInvoice() {
        System.out.println("生成发票");
    }
    
    protected void validateStock() {
        System.out.println("验证库存");
    }
    
    protected void updateInventory() {
        System.out.println("更新库存");
    }
}

/**
 * 简化后的订单服务
 */
public class OrderService {
    
    public void processOrder(OrderType orderType) {
        // 一行代码完成所有处理
        orderType.process();
    }


}

// 使用示例
OrderService service = new OrderService();
service.processOrder(OrderType.ONLINE);
service.processOrder(OrderType.WHOLESALE);

3. 使用策略模式 + 枚举

java
/**
 * 订单处理策略接口
 */
public interface OrderProcessor {
    void process();
}

/**
 * 在线订单处理器
 */
public class OnlineOrderProcessor implements OrderProcessor {
    @Override
    public void process() {
        System.out.println("处理在线订单");
        // 具体实现
    }
}

/**
 * 线下订单处理器
 */
public class OfflineOrderProcessor implements OrderProcessor {
    @Override
    public void process() {
        System.out.println("处理线下订单");
        // 具体实现
    }
}

/**
 * 枚举关联策略
 */
public enum OrderType {
    ONLINE("在线订单", new OnlineOrderProcessor()),
    OFFLINE("线下订单", new OfflineOrderProcessor()),
    WHOLESALE("批发订单", new WholesaleOrderProcessor()),
    RETAIL("零售订单", new RetailOrderProcessor());
    
    private final String description;
    private final OrderProcessor processor;
    
    OrderType(String description, OrderProcessor processor) {
        this.description = description;
        this.processor = processor;
    }
    
    public void process() {
        processor.process();
    }
    
    public String getDescription() {
        return description;
    }
}

🚀 高级用法

1. 枚举实现接口

java
/**
 * 计算策略接口
 */
public interface Calculator {
    double calculate(double a, double b);
}

/**
 * 运算符枚举
 */
public enum Operator implements Calculator {
    
    ADD("+") {
        @Override
        public double calculate(double a, double b) {
            return a + b;
        }
    },
    
    SUBTRACT("-") {
        @Override
        public double calculate(double a, double b) {
            return a - b;
        }
    },
    
    MULTIPLY("*") {
        @Override
        public double calculate(double a, double b) {
            return a * b;
        }
    },
    
    DIVIDE("/") {
        @Override
        public double calculate(double a, double b) {
            if (b == 0) {
                throw new ArithmeticException("除数不能为零");
            }
            return a / b;
        }
    };
    
    private final String symbol;
    
    Operator(String symbol) {
        this.symbol = symbol;
    }
    
    public String getSymbol() {
        return symbol;
    }
    
    /**
     * 根据符号获取运算符
     */
    public static Operator fromSymbol(String symbol) {
        for (Operator op : values()) {
            if (op.symbol.equals(symbol)) {
                return op;
            }
        }
        throw new IllegalArgumentException("未知的运算符: " + symbol);
    }
}

// 使用示例
public class CalculatorDemo {
    public static void main(String[] args) {
        double result1 = Operator.ADD.calculate(10, 5);        // 15.0
        double result2 = Operator.MULTIPLY.calculate(10, 5);   // 50.0
        
        // 动态选择运算符
        Operator op = Operator.fromSymbol("+");
        double result3 = op.calculate(10, 5);                  // 15.0
    }
}

2. 枚举 + Map 映射

java
/**
 * 支付方式枚举
 */
public enum PaymentMethod {
    ALIPAY("支付宝", "alipay"),
    WECHAT("微信支付", "wechat"),
    CREDIT_CARD("信用卡", "credit_card"),
    CASH("现金", "cash");
    
    private final String name;
    private final String code;
    
    // 静态 Map 用于快速查找
    private static final Map<String, PaymentMethod> CODE_MAP = new HashMap<>();
    
    static {
        for (PaymentMethod method : values()) {
            CODE_MAP.put(method.code, method);
        }
    }
    
    PaymentMethod(String name, String code) {
        this.name = name;
        this.code = code;
    }
    
    public String getName() {
        return name;
    }
    
    public String getCode() {
        return code;
    }
    
    /**
     * 根据代码获取支付方式(O(1) 时间复杂度)
     */
    public static PaymentMethod fromCode(String code) {
        PaymentMethod method = CODE_MAP.get(code);
        if (method == null) {
            throw new IllegalArgumentException("未知的支付方式代码: " + code);
        }
        return method;
    }
    
    /**
     * 处理支付
     */
    public void processPayment(double amount) {
        System.out.println("使用" + name + "支付: ¥" + amount);
        // 具体支付逻辑
    }
}

// 使用示例
public class PaymentDemo {
    public static void main(String[] args) {
        // 从外部系统获取支付代码
        String paymentCode = "alipay";
        
        // 快速查找并处理
        PaymentMethod method = PaymentMethod.fromCode(paymentCode);
        method.processPayment(100.00);
    }
}

3. 枚举单例模式

java
/**
 * 使用枚举实现线程安全的单例
 */
public enum DatabaseConnection {
    INSTANCE;
    
    private Connection connection;
    
    DatabaseConnection() {
        // 初始化数据库连接
        try {
            this.connection = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/mydb",
                "username",
                "password"
            );
        } catch (SQLException e) {
            throw new RuntimeException("数据库连接失败", e);
        }
    }
    
    public Connection getConnection() {
        return connection;
    }
    
    public void executeQuery(String sql) {
        // 执行查询
        System.out.println("执行SQL: " + sql);
    }
}

// 使用示例
DatabaseConnection.INSTANCE.executeQuery("SELECT * FROM users");

💼 实战案例

案例 1:订单状态流转

java
/**
 * 订单状态枚举
 */
public enum OrderStatus {
    
    PENDING("待支付") {
        @Override
        public OrderStatus next() {
            return PAID;
        }
        
        @Override
        public boolean canCancel() {
            return true;
        }
    },
    
    PAID("已支付") {
        @Override
        public OrderStatus next() {
            return SHIPPING;
        }
        
        @Override
        public boolean canCancel() {
            return true;
        }
    },
    
    SHIPPING("配送中") {
        @Override
        public OrderStatus next() {
            return DELIVERED;
        }
        
        @Override
        public boolean canCancel() {
            return false;
        }
    },
    
    DELIVERED("已送达") {
        @Override
        public OrderStatus next() {
            return COMPLETED;
        }
        
        @Override
        public boolean canCancel() {
            return false;
        }
    },
    
    COMPLETED("已完成") {
        @Override
        public OrderStatus next() {
            throw new IllegalStateException("订单已完成,无法继续流转");
        }
        
        @Override
        public boolean canCancel() {
            return false;
        }
    },
    
    CANCELLED("已取消") {
        @Override
        public OrderStatus next() {
            throw new IllegalStateException("订单已取消,无法继续流转");
        }
        
        @Override
        public boolean canCancel() {
            return false;
        }
    };
    
    private final String description;
    
    OrderStatus(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
    
    /**
     * 获取下一个状态
     */
    public abstract OrderStatus next();
    
    /**
     * 是否可以取消
     */
    public abstract boolean canCancel();
    
    /**
     * 取消订单
     */
    public OrderStatus cancel() {
        if (!canCancel()) {
            throw new IllegalStateException("当前状态不允许取消订单");
        }
        return CANCELLED;
    }
}

/**
 * 订单实体
 */
public class Order {
    private String orderId;
    private OrderStatus status;
    
    public Order(String orderId) {
        this.orderId = orderId;
        this.status = OrderStatus.PENDING;
    }
    
    /**
     * 流转到下一个状态
     */
    public void moveToNext() {
        System.out.println("订单 " + orderId + " 从 " + status.getDescription() 
            + " 流转到 " + status.next().getDescription());
        this.status = status.next();
    }
    
    /**
     * 取消订单
     */
    public void cancel() {
        System.out.println("取消订单 " + orderId);
        this.status = status.cancel();
    }
    
    public OrderStatus getStatus() {
        return status;
    }
}

// 使用示例
public class OrderDemo {
    public static void main(String[] args) {
        Order order = new Order("ORD001");
        
        order.moveToNext();  // 待支付 -> 已支付
        order.moveToNext();  // 已支付 -> 配送中
        
        try {
            order.cancel();  // 配送中不能取消
        } catch (IllegalStateException e) {
            System.out.println("错误: " + e.getMessage());
        }
        
        order.moveToNext();  // 配送中 -> 已送达
        order.moveToNext();  // 已送达 -> 已完成
    }
}

案例 2:HTTP 响应状态码

java
/**
 * HTTP 状态码枚举
 */
public enum HttpStatus {
    
    // 2xx 成功
    OK(200, "成功") {
        @Override
        public boolean isSuccess() {
            return true;
        }
    },
    CREATED(201, "已创建") {
        @Override
        public boolean isSuccess() {
            return true;
        }
    },
    
    // 4xx 客户端错误
    BAD_REQUEST(400, "错误的请求") {
        @Override
        public boolean isClientError() {
            return true;
        }
    },
    UNAUTHORIZED(401, "未授权") {
        @Override
        public boolean isClientError() {
            return true;
        }
    },
    FORBIDDEN(403, "禁止访问") {
        @Override
        public boolean isClientError() {
            return true;
        }
    },
    NOT_FOUND(404, "未找到") {
        @Override
        public boolean isClientError() {
            return true;
        }
    },
    
    // 5xx 服务器错误
    INTERNAL_SERVER_ERROR(500, "服务器内部错误") {
        @Override
        public boolean isServerError() {
            return true;
        }
    },
    SERVICE_UNAVAILABLE(503, "服务不可用") {
        @Override
        public boolean isServerError() {
            return true;
        }
    };
    
    private final int code;
    private final String message;
    
    private static final Map<Integer, HttpStatus> CODE_MAP = new HashMap<>();
    
    static {
        for (HttpStatus status : values()) {
            CODE_MAP.put(status.code, status);
        }
    }
    
    HttpStatus(int code, String message) {
        this.code = code;
        this.message = message;
    }
    
    public int getCode() {
        return code;
    }
    
    public String getMessage() {
        return message;
    }
    
    public boolean isSuccess() {
        return false;
    }
    
    public boolean isClientError() {
        return false;
    }
    
    public boolean isServerError() {
        return false;
    }
    
    /**
     * 根据状态码获取枚举
     */
    public static HttpStatus fromCode(int code) {
        HttpStatus status = CODE_MAP.get(code);
        if (status == null) {
            throw new IllegalArgumentException("未知的HTTP状态码: " + code);
        }
        return status;
    }
    
    /**
     * 处理响应
     */
    public void handleResponse() {
        if (isSuccess()) {
            System.out.println("请求成功: " + message);
        } else if (isClientError()) {
            System.out.println("客户端错误: " + message);
        } else if (isServerError()) {
            System.out.println("服务器错误: " + message);
        }
    }
}

// 使用示例
public class HttpDemo {
    public static void main(String[] args) {
        HttpStatus status = HttpStatus.fromCode(404);
        status.handleResponse();  // 客户端错误: 未找到
        
        if (status.isClientError()) {
            System.out.println("需要检查请求参数");
        }
    }
}

案例 3:权限验证

java
/**
 * 用户角色枚举
 */
public enum UserRole {
    
    ADMIN("管理员") {
        @Override
        public boolean hasPermission(String resource, String action) {
            // 管理员拥有所有权限
            return true;
        }
    },
    
    MANAGER("经理") {
        @Override
        public boolean hasPermission(String resource, String action) {
            // 经理可以查看和编辑,但不能删除
            return "view".equals(action) || "edit".equals(action);
        }
    },
    
    USER("普通用户") {
        @Override
        public boolean hasPermission(String resource, String action) {
            // 普通用户只能查看
            return "view".equals(action);
        }
    },
    
    GUEST("访客") {
        @Override
        public boolean hasPermission(String resource, String action) {
            // 访客只能查看公开资源
            return "view".equals(action) && "public".equals(resource);
        }
    };
    
    private final String description;
    
    UserRole(String description) {
        this.description = description;
    }
    
    public String getDescription(){
        return description;
    }
    
    /**
     * 检查权限
     */
    public abstract boolean hasPermission(String resource, String action);
    
    /**
     * 执行操作
     */
    public void performAction(String resource, String action) {
        if (hasPermission(resource, action)) {
            System.out.println(description + " 对 " + resource + " 执行 " + action + " 操作");
        } else {
            throw new SecurityException(description + " 没有权限执行此操作");
        }
    }
}

// 使用示例
public class PermissionDemo {
    public static void main(String[] args) {
        UserRole admin = UserRole.ADMIN;
        UserRole user = UserRole.USER;
        
        admin.performAction("document", "delete");  // 成功
        
        try {
            user.performAction("document", "delete");  // 抛出异常
        } catch (SecurityException e) {
            System.out.println("错误: " + e.getMessage());
        }
    }
}

💡 最佳实践

1. 何时使用枚举替代 if-else

✅ 适合使用枚举的场景

java
// ✅ 固定的、有限的选项
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}

// ✅ 状态机
public enum TrafficLight {
    RED, YELLOW, GREEN
}

// ✅ 类型分类
public enum FileType {
    PDF, DOCX, XLSX, JPG, PNG
}

// ✅ 配置选项
public enum LogLevel {
    DEBUG, INFO, WARN, ERROR
}

❌ 不适合使用枚举的场景

java
// ❌ 动态变化的值
// 不要用枚举表示用户ID、订单号等

// ❌ 数量不确定的选项
// 不要用枚举表示数据库中的动态分类

// ❌ 需要频繁修改的业务规则
// 考虑使用策略模式 + 配置文件

2. 枚举设计原则

单一职责原则

java
// ✅ 好的设计:枚举只负责类型定义
public enum OrderType {
    ONLINE, OFFLINE, WHOLESALE, RETAIL;
    
    public String getDescription() {
        return name();
    }
}

// 处理逻辑放在专门的处理器中
public class OrderProcessor {
    public void process(OrderType type) {
        // 处理逻辑
    }
}

// ❌ 不好的设计:枚举包含太多业务逻辑
public enum OrderType {
    ONLINE {
        public void process() {
            // 大量业务逻辑...
            // 数据库操作...
            // 外部API调用...
        }
    }
}

避免过度设计

java
// ✅ 简单场景用简单实现
public enum Status {
    ACTIVE, INACTIVE;
    
    public boolean isActive() {
        return this == ACTIVE;
    }
}

// ❌ 不要过度设计
public enum Status {
    ACTIVE("激活", 1, true, "active") {
        @Override
        public void doSomething() {
            // 复杂逻辑...
        }
    };
    
    // 过多的字段和方法...
}

3. 性能优化

使用 EnumSet 和 EnumMap

java
/**
 * 使用 EnumSet 进行集合操作
 */
public class EnumSetDemo {
    
    public enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    public static void main(String[] args) {
        // EnumSet 比 HashSet 更高效
        EnumSet<Day> weekdays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
        EnumSet<Day> weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);
        
        System.out.println("工作日: " + weekdays);
        System.out.println("周末: " + weekend);
    }
}

/**
 * 使用 EnumMap 进行映射
 */
public class EnumMapDemo {
    
    public enum Color {
        RED, GREEN, BLUE
    }
    
    public static void main(String[] args) {
        // EnumMap 比 HashMap 更高效
        EnumMap<Color, String> colorMap = new EnumMap<>(Color.class);
        colorMap.put(Color.RED, "#FF0000");
        colorMap.put(Color.GREEN, "#00FF00");
        colorMap.put(Color.BLUE, "#0000FF");
        
        System.out.println("红色代码: " + colorMap.get(Color.RED));
    }
}

缓存策略

java
/**
 * 枚举中使用静态缓存
 */
public enum CachedEnum {
    TYPE_A, TYPE_B, TYPE_C;
    
    // 缓存计算结果
    private static final Map<CachedEnum, String> CACHE = new EnumMap<>(CachedEnum.class);
    
    static {
        for (CachedEnum type : values()) {
            CACHE.put(type, computeExpensiveValue(type));
        }
    }
    
    private static String computeExpensiveValue(CachedEnum type) {
        // 耗时计算
        return "Computed value for " + type;
    }
    
    public String getCachedValue() {
        return CACHE.get(this);
    }
}

4. 线程安全

java
/**
 * 枚举天然线程安全
 */
public enum ThreadSafeSingleton {
    INSTANCE;
    
    private final AtomicInteger counter = new AtomicInteger(0);
    
    public int incrementAndGet() {
        return counter.incrementAndGet();
    }
}

// 多线程环境下安全使用
public class ConcurrentDemo {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        
        for (int i = 0; i < 100; i++) {
            executor.submit(() -> {
                int count = ThreadSafeSingleton.INSTANCE.incrementAndGet();
                System.out.println("Count: " + count);
            });
        }
        
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
    }
}

📊 对比总结

传统 if-else vs 枚举

维度if-else枚举
代码可读性❌ 差✅ 好
类型安全❌ 无✅ 有
编译检查❌ 运行时错误✅ 编译时检查
扩展性❌ 难以扩展✅ 易于扩展
维护成本❌ 高✅ 低
性能✅ 略快✅ 相当
IDE支持❌ 弱✅ 强

代码行数对比

java
// 传统 if-else:50+ 行
public void processOrder(String type) {
    if ("ONLINE".equals(type)) {
        // 10行代码
    } else if ("OFFLINE".equals(type)) {
        // 10行代码
    } else if ("WHOLESALE".equals(type)) {
        // 10行代码
    } else if ("RETAIL".equals(type)) {
        // 10行代码
    } else {
        throw new IllegalArgumentException("未知类型");
    }
}

// 枚举方案:1 行
public void processOrder(OrderType type) {
    type.process();  // 逻辑封装在枚举中
}

🎯 常见问题

Q1: 枚举可以继承吗?

答: 不可以。Java 中的枚举隐式继承自 java.lang.Enum,不能再继承其他类。但可以实现接口。

java
// ❌ 错误:枚举不能继承类
public enum MyEnum extends SomeClass {  // 编译错误
}

// ✅ 正确:枚举可以实现接口
public enum MyEnum implements MyInterface {
    INSTANCE;
    
    @Override
    public void method() {
        // 实现接口方法
    }
}

Q2: 如何序列化枚举?

答: 枚举天然支持序列化,且保证单例特性。

java
public enum Status implements Serializable {
    ACTIVE, INACTIVE;
}

// 序列化和反序列化后,仍然是同一个实例
Status original = Status.ACTIVE;
// 序列化...
// 反序列化...
Status deserialized = ...;
System.out.println(original == deserialized);  // true

Q3: 枚举的性能如何?

答: 枚举的性能非常好:

java
// 1. 枚举比较使用 == 而不是 equals()
if (status == Status.ACTIVE) {  // 非常快
}

// 2. switch 语句对枚举优化
switch (status) {  // 编译器优化,使用跳转表
    case ACTIVE: break;
    case INACTIVE: break;
}

// 3. EnumSet 和 EnumMap 是专门优化的集合类
EnumSet<Day> set = EnumSet.of(Day.MONDAY);  // 位向量实现,极快

Q4: 枚举占用内存吗?

答: 枚举实例在类加载时创建,全局只有一份,内存占用很小。

java
public enum Color {
    RED, GREEN, BLUE;  // 只创建3个实例,全局共享
}

📚 学习资源

官方文档

推荐阅读

  • 《Effective Java》第三版 - Joshua Bloch
  • 《Java核心技术》卷I - Cay S. Horstmann
  • 《重构:改善既有代码的设计》- Martin Fowler

相关设计模式

  • 策略模式:枚举 + 接口实现不同策略
  • 状态模式:枚举表示不同状态及其行为
  • 单例模式:枚举实现线程安全的单例

✅ 检查清单

在重构 if-else 为枚举之前,请检查:

  • [ ] 选项是固定的、有限的
  • [ ] 不会频繁增删选项
  • [ ] 需要类型安全
  • [ ] 需要更好的可读性和可维护性
  • [ ] 每个选项有特定的行为或属性
  • [ ] 希望利用编译时检查

🎓 总结

核心要点

  1. 类型安全:枚举提供编译时类型检查,避免字符串常量的拼写错误
  2. 代码简洁:将行为封装在枚举中,消除冗长的 if-else
  3. 易于维护:修改只需要在枚举类中进行,不影响使用方
  4. 性能优良:枚举比较使用 ==,switch 语句有编译器优化
  5. 功能强大:可以包含字段、方法、实现接口

实践建议

  1. 优先考虑枚举:当有固定选项时,首选枚举而非字符串或整数常量
  2. 封装行为:将相关行为封装在枚举中,而不是在调用方使用 switch
  3. 使用接口:当多个枚举有共同行为时,使用接口统一
  4. 合理设计:不要让枚举承担过多职责,保持单一职责原则
  5. 利用工具类:使用 EnumSet 和 EnumMap 提升性能

重构步骤

1. 识别 if-else 中的固定选项
2. 创建枚举类,定义所有选项
3. 为每个选项添加必要的属性和方法
4. 将原有的 if-else 逻辑迁移到枚举中
5. 修改调用方代码,使用枚举替代字符串
6. 测试验证功能正确性
7. 清理旧代码

💻 完整示例代码

重构前

java
public class OrderServiceBefore {
    public void processOrder(String orderType) {
        if ("ONLINE".equals(orderType)) {
            System.out.println("处理在线订单");
            validateOnlinePayment();
            sendEmail();
        } else if ("OFFLINE".equals(orderType)) {
            System.out.println("处理线下订单");
            validateCash();
            printReceipt();
        } else if ("WHOLESALE".equals(orderType)) {
            System.out.println("处理批发订单");
            checkCredit();
            generateInvoice();
        } else {
            throw new IllegalArgumentException("未知订单类型");
        }
    }
}

重构后

java
public enum OrderType {
    ONLINE("在线订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            validateOnlinePayment();
            sendEmail();
        }
    },
    OFFLINE("线下订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            validateCash();
            printReceipt();
        }
    },
    WHOLESALE("批发订单") {
        @Override
        public void process() {
            System.out.println("处理" + getDescription());
            checkCredit();
            generateInvoice();
        }
    };
    
    private final String description;
    
    OrderType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
    
    public abstract void process();
    
    protected void validateOnlinePayment() {
        System.out.println("验证在线支付");
    }
    
    protected void sendEmail() {
        System.out.println("发送邮件");
    }
    
    protected void validateCash() {
        System.out.println("验证现金");
    }
    
    protected void printReceipt() {
        System.out.println("打印收据");
    }
    
    protected void checkCredit() {
        System.out.println("检查信用");
    }
    
    protected void generateInvoice() {
        System.out.println("生成发票");
    }
}

public class OrderServiceAfter {
    public void processOrder(OrderType orderType) {
        orderType.process();  // 一行代码搞定!
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        OrderServiceAfter service = new OrderServiceAfter();
        
        // 类型安全,编译时检查
        service.processOrder(OrderType.ONLINE);
        service.processOrder(OrderType.WHOLESALE);
        
        // service.processOrder("INVALID");  // 编译错误!
    }
}

🚀 下一步

  1. 识别项目中的 if-else 代码

    • 使用 IDE 搜索功能查找长 if-else 链
    • 关注业务逻辑中的类型判断
  2. 评估重构价值

    • 判断选项是否固定
    • 评估维护成本和收益
  3. 逐步重构

    • 从简单场景开始
    • 编写测试用例
    • 渐进式替换
  4. 团队分享

    • 分享重构经验
    • 建立团队规范
    • Code Review 中关注

最后更新:2025年

本文档持续更新中,欢迎提供反馈和建议。

Released under the MIT License.