优化if else过多的方案(含设计模式处理方式)

文章目录

  • 问题描述
  • 解决思路
  • 具体实现示例
    • [1. 策略模式](#1. 策略模式)
    • [2. 工厂+策略(结合 Map)](#2. 工厂+策略(结合 Map))
    • [3. 使用枚举 + 函数式接口](#3. 使用枚举 + 函数式接口)
    • [4. 责任链模式](#4. 责任链模式)
    • [5. 状态模式](#5. 状态模式)
  • 总结

问题描述

经常遇到,根据某个条件执行不同逻辑的需求。

例如:

java 复制代码
public void handle(String type) {
    if (type.equals("A")) {
        // 逻辑 A
    } else if (type.equals("B")) {
        // 逻辑 B
    } else if (type.equals("C")) {
        // 逻辑 C
    } else {
        // 默认逻辑
    }
}

当条件数量增加时,这段代码会变长、不易维护、不符合开闭原则(增加新的条件需修改原有代码)。

解决思路

常见的方法是将判断逻辑转换为对象的多态行为,或者用查找表(Map)代替条件分支。

主要有以下几种模式:

  • 策略模式(Strategy Pattern)

  • 工厂模式 + 策略模式

  • 状态模式(State Pattern)(适用于状态流转场景)

  • 责任链模式(Chain of Responsibility Pattern)

  • 使用 Map 消除分支(结合枚举、函数式接口)

具体实现示例

假设有一个订单处理系统,不同类型的订单(普通、VIP、预售)需要不同的折扣计算方式。

1. 策略模式

定义一个策略接口:

java 复制代码
public interface DiscountStrategy {
    double calculate(double price);
}

具体策略:

java 复制代码
public class NormalDiscount implements DiscountStrategy {
    public double calculate(double price) {
        return price * 0.9;  // 9折
    }
}

public class VipDiscount implements DiscountStrategy {
    public double calculate(double price) {
        return price * 0.8;  // 8折
    }
}

public class PreSaleDiscount implements DiscountStrategy {
    public double calculate(double price) {
        return price * 0.85; // 85折
    }
}

上下文(Context)使用策略:

java 复制代码
public class OrderService {
    private DiscountStrategy strategy;

    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public double applyDiscount(double price) {
        return strategy.calculate(price);
    }
}

客户端使用时决定用哪种策略:

java 复制代码
OrderService service = new OrderService();
service.setStrategy(new VipDiscount());
double result = service.applyDiscount(100);

2. 工厂+策略(结合 Map)

引入一个策略工厂,负责根据类型返回策略实例,消灭调用方的分支:

java 复制代码
public class DiscountStrategyFactory {
    private static Map<String, DiscountStrategy> strategies = new HashMap<>();

    static {
        strategies.put("NORMAL", new NormalDiscount());
        strategies.put("VIP", new VipDiscount());
        strategies.put("PRE_SALE", new PreSaleDiscount());
    }

    public static DiscountStrategy getStrategy(String type) {
        DiscountStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("未知类型");
        }
        return strategy;
    }
}

调用方只需:

java 复制代码
DiscountStrategy strategy = DiscountStrategyFactory.getStrategy("VIP");
double result = strategy.calculate(100);

这样原来的一长串 if-else 就变成了一个 Map 查找,扩展时只需在 static 块增加一条映射。

3. 使用枚举 + 函数式接口

使用枚举来持有策略:

java 复制代码
public enum OrderType {
    NORMAL(price -> price * 0.9),
    VIP(price -> price * 0.8),
    PRE_SALE(price -> price * 0.85);

    private final DiscountStrategy strategy;

    OrderType(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public double applyDiscount(double price) {
        return strategy.calculate(price);
    }
}

其中 DiscountStrategy 可以是一个函数式接口:

java 复制代码
@FunctionalInterface
public interface DiscountStrategy {
    double calculate(double price);
}

使用:

java 复制代码
double price = 100;
OrderType type = OrderType.VIP;
double result = type.applyDiscount(price);

4. 责任链模式

当流程是顺序判断,并且每个处理器可以选择自己处理或交给下一个,可以用责任链模式。

例如:假设公司采购审批规则如下:

  • 采购金额 ≤ 1000元:组长审批即可

  • 1000元 < 金额 ≤ 5000元:需要经理审批

  • 5000元 < 金额 ≤ 20000元:需要总监审批

  • 金额 > 20000元:需要总经理审批

  1. 定义审批请求类
java 复制代码
// 采购请求
public class PurchaseRequest {
    private double amount;      // 采购金额
    private String purpose;     // 采购目的
    private int id;             // 请求编号

    public PurchaseRequest(double amount, String purpose, int id) {
        this.amount = amount;
        this.purpose = purpose;
        this.id = id;
    }

    public double getAmount() { return amount; }
    public String getPurpose() { return purpose; }
    public int getId() { return id; }
}
  1. 定义审批人抽象类
java 复制代码
public abstract class Approver {
    protected Approver nextApprover;  // 下一个审批人
    protected String name;             // 审批人姓名
    protected String position;         // 职位

    public Approver(String name, String position) {
        this.name = name;
        this.position = position;
    }

    // 设置下一个审批人
    public void setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
    }

    // 审批请求的抽象方法
    public abstract void processRequest(PurchaseRequest request);

    // 转发给下一个审批人
    protected void forwardToNext(PurchaseRequest request) {
        if (nextApprover != null) {
            System.out.println("【" + position + " " + name + "】无权审批,已转交给下一级");
            nextApprover.processRequest(request);
        } else {
            System.out.println("【审批失败】没有合适的审批人处理该请求");
        }
    }
}
  1. 实现具体审批人
java 复制代码
// 组长审批
public class TeamLeader extends Approver {
    
    public TeamLeader(String name) {
        super(name, "组长");
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 1000) {
            System.out.println("【组长 " + name + "】审批通过:采购单 #" + request.getId() + 
                             ",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
        } else {
            forwardToNext(request);
        }
    }
}

// 经理审批
public class Manager extends Approver {
    
    public Manager(String name) {
        super(name, "经理");
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 5000) {
            System.out.println("【经理 " + name + "】审批通过:采购单 #" + request.getId() + 
                             ",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
        } else {
            forwardToNext(request);
        }
    }
}

// 总监审批
public class Director extends Approver {
    
    public Director(String name) {
        super(name, "总监");
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 20000) {
            System.out.println("【总监 " + name + "】审批通过:采购单 #" + request.getId() + 
                             ",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
        } else {
            forwardToNext(request);
        }
    }
}

// 总经理审批

public class GeneralManager extends Approver {
    
    public GeneralManager(String name) {
        super(name, "总经理");
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= 100000) {
            System.out.println("【总经理 " + name + "】审批通过:采购单 #" + request.getId() + 
                             ",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
        } else {
            System.out.println("【审批拒绝】采购金额 " + request.getAmount() + 
                             "元超出总经理权限,需董事会审批");
        }
    }
}
  1. 使用
java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建审批人
        TeamLeader teamLeader = new TeamLeader("张三");
        Manager manager = new Manager("李四");
        Director director = new Director("王五");
        GeneralManager generalManager = new GeneralManager("赵六");

        // 构建责任链
        teamLeader.setNextApprover(manager);
        manager.setNextApprover(director);
        director.setNextApprover(generalManager);

        // 创建采购请求
        PurchaseRequest request1 = new PurchaseRequest(800, "办公用品", 1001);
        PurchaseRequest request2 = new PurchaseRequest(3000, "电脑设备", 1002);
        PurchaseRequest request3 = new PurchaseRequest(15000, "服务器", 1003);
        PurchaseRequest request4 = new PurchaseRequest(50000, "装修工程", 1004);

        // 从链首开始处理
        System.out.println("=== 处理采购单 1001 ===");
        teamLeader.processRequest(request1);
        
        System.out.println("\n=== 处理采购单 1002 ===");
        teamLeader.processRequest(request2);
        
        System.out.println("\n=== 处理采购单 1003 ===");
        teamLeader.processRequest(request3);
        
        System.out.println("\n=== 处理采购单 1004 ===");
        teamLeader.processRequest(request4);
    }
}

5. 状态模式

如果对象在不同状态下行为不同,而且状态会切换,则使用状态模式。

例如订单有「待付款」「已付款」「已发货」「已完成」等状态,每种状态下的操作行为不同。待付款 → 已付款 → 已发货 → 已完成

  1. 定义订单上下文
java 复制代码
// 订单类(上下文)
public class Order {
    private OrderState currentState;  // 当前状态
    private int orderId;
    private double amount;

    public Order(int orderId, double amount) {
        this.orderId = orderId;
        this.amount = amount;
        // 初始状态为待付款
        this.currentState = new PendingPaymentState();
        System.out.println("创建订单 #" + orderId + ",金额:" + amount + "元,当前状态:待付款");
    }

    public void setState(OrderState state) {
        this.currentState = state;
    }

    public int getOrderId() { return orderId; }
    public double getAmount() { return amount; }

    // 状态相关的方法委托给当前状态对象处理
    public void pay() {
        currentState.pay(this);
    }

    public void ship() {
        currentState.ship(this);
    }

    public void confirmReceipt() {
        currentState.confirmReceipt(this);
    }

    public void cancel() {
        currentState.cancel(this);
    }
}
  1. 定义状态接口
java 复制代码
public interface OrderState {
    // 支付
    void pay(Order order);
    // 发货
    void ship(Order order);
    // 确认收货
    void confirmReceipt(Order order);
    // 取消订单
    void cancel(Order order);
    
    // 获取状态名称
    String getStateName();
}
  1. 实现具体状态类
java 复制代码
// 待付款状态
public class PendingPaymentState implements OrderState {
    
    @Override
    public void pay(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 支付成功,金额:" + order.getAmount() + "元");
        // 状态流转:待付款 → 已付款
        order.setState(new PaidState());
        System.out.println("订单状态变更为:已付款");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 尚未付款,不能发货");
    }

    @Override
    public void confirmReceipt(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 尚未付款,不能确认收货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 取消成功");
        order.setState(new CancelledState());
        System.out.println("订单状态变更为:已取消");
    }

    @Override
    public String getStateName() {
        return "待付款";
    }
}

// 已付款状态
public class PaidState implements OrderState {
    
    @Override
    public void pay(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已付款,请勿重复支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 发货成功");
        // 状态流转:已付款 → 已发货
        order.setState(new ShippedState());
        System.out.println("订单状态变更为:已发货");
    }

    @Override
    public void confirmReceipt(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 尚未发货,不能确认收货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 申请退款成功,订单取消");
        order.setState(new CancelledState());
        System.out.println("订单状态变更为:已取消");
    }

    @Override
    public String getStateName() {
        return "已付款";
    }
}

// 已发货状态
public class ShippedState implements OrderState {
    
    @Override
    public void pay(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已发货,无需支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已发货,请勿重复发货");
    }

    @Override
    public void confirmReceipt(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 确认收货成功");
        // 状态流转:已发货 → 已完成
        order.setState(new CompletedState());
        System.out.println("订单状态变更为:已完成");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已发货,不能取消,如需退货请申请售后");
    }

    @Override
    public String getStateName() {
        return "已发货";
    }
}

// 已完成状态
public class CompletedState implements OrderState {
    
    @Override
    public void pay(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已完成,无需支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已完成,不能发货");
    }

    @Override
    public void confirmReceipt(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已完成,请勿重复确认收货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已完成,不能取消");
    }

    @Override
    public String getStateName() {
        return "已完成";
    }
}

// 已取消状态
public class CancelledState implements OrderState {
    
    @Override
    public void pay(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已取消,不能支付");
    }

    @Override
    public void ship(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已取消,不能发货");
    }

    @Override
    public void confirmReceipt(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已取消,不能确认收货");
    }

    @Override
    public void cancel(Order order) {
        System.out.println("订单 #" + order.getOrderId() + " 已取消,请勿重复取消");
    }

    @Override
    public String getStateName() {
        return "已取消";
    }
}
  1. 测试
java 复制代码
public class OrderTest {
    public static void main(String[] args) {
        // 创建新订单
        Order order = new Order(10001, 299.9);
        
        System.out.println("\n=== 测试支付 ===");
        order.pay();  // 待付款 → 支付
        
        System.out.println("\n=== 测试重复支付 ===");
        order.pay();  // 已付款状态,不能重复支付
        
        System.out.println("\n=== 测试发货 ===");
        order.ship(); // 已付款 → 发货
        
        System.out.println("\n=== 测试确认收货 ===");
        order.confirmReceipt(); // 已发货 → 已完成
        
        System.out.println("\n=== 测试取消已完成订单 ===");
        order.cancel(); // 已完成,不能取消
        
        System.out.println("\n=== 创建另一个订单测试取消流程 ===");
        Order order2 = new Order(10002, 599.9);
        order2.pay();  // 支付
        order2.cancel(); // 已付款状态可以取消
    }
}

本质是把状态对应的行为封装到不同的状态类中,用组合代替分支。

总结

  1. 策略模式、工厂模式、枚举类 :都属于将可能的情况都列出来,然后根据不同的情况执行不同的方法 。
  2. 责任链模型 :适用于有顺序要求的情况,能够定义下一个处理对象。
  3. 状态模式:也是对顺序有一定要求,每个状态都对其他状态设置了处理方法。

github代码地址:https://github.com/TimberWill/design-patterns

以上为个人学习分享,如有问题,欢迎指出:)

相关推荐
@insist1232 小时前
软件设计师-结构型与行为型设计模式全解:软考设计模式考点一站式通关
设计模式·软考·软件设计师·软件水平考试
东离与糖宝2 小时前
GraalVM+Project Leyden实战:Spring Boot应用原生编译,Serverless冷启动自由
java·人工智能
今天你TLE了吗3 小时前
JVM学习笔记:第七章——对象实例化、内存布局&访问定位
java·jvm·笔记·学习
w_t_y_y3 小时前
知识体系——MCP(三)io.modelcontextprotocol.sdk(1)开发mcp server
java
亚马逊云开发者3 小时前
人人都能写 OpenClaw Skill!手把手带你做一个自动日报技能
java
weixin_399380693 小时前
Prometheus(普罗米修斯)+grafana 监控Tongweb80909(by lqw)
java·grafana·prometheus
9527出列3 小时前
结合拦截器描述mybatis启动流程
java·mybatis
blues92573 小时前
MySQL 篇 - Java 连接 MySQL 数据库并实现数据交互
java·数据库·mysql
9527出列3 小时前
Redis系列--实现一个简单的redis分布式锁
java·redis