Strategy策略模式优化业务代码

358 阅读2分钟

    项目里有一个关于计算佣金的需求,之前已经有15个分支了,这次再来个分支就16个分支了,之前15个分支在圈复杂度上肯定是过不去的,没办法就拆成2部分去临时规避一下,现在正好又要这块需求,于是决定采用策略模式进行整改

   策略模式:定义一系列算法分别封装起来,让他们之间可以项目替换,算法的改变不会影响使用算法的用户

上下文对象
package com.my.test.design.strategy.Commission;

public class CommissionContext {

    /**
     *  代理商名称
     */
    private String agentName;

    /**
     * 佣金比例
     */
    private double rate;

    /**
     *  总金额
     */
    private double totalAmount;

    /**
     * 策略
     */
    private CommissionStrategy strategy;

    public String getAgentName() {
        return agentName;
    }

    public void setAgentName(String agentName) {
        this.agentName = agentName;
    }

    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }

    public double getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(double totalAmount) {
        this.totalAmount = totalAmount;
    }

    public CommissionStrategy getStrategy() {
        return strategy;
    }

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

    // 计算佣金的时候我们需要从上下文对象中获取信息
    public void getCommission(CommissionStrategy strategy){
        strategy.getCommission(this);
    }
}

抽象的策略接口
public interface CommissionStrategy {

    void getCommission(CommissionContext context);
}

具体策略A
public class CommissionA implements CommissionStrategy {
    @Override
    public void getCommission(CommissionContext context) {
        System.out.println("A的佣金算法业务代码");
        System.out.println(context.getAgentName()+"的佣金是"+context.getTotalAmount()
                *context.getRate()*0.2);
    }
}

具体策略B
public class CommissionB implements CommissionStrategy {
    @Override
    public void getCommission(CommissionContext context) {
        System.out.println("B的佣金算法业务代码");
        System.out.println(context.getAgentName()+"的佣金是"+context.getTotalAmount()
                *context.getRate()*0.3);

    }
}

具体策略C
public class CommissionC implements CommissionStrategy {
    @Override
    public void getCommission(CommissionContext context) {
        System.out.println("C的佣金算法业务代码");
        System.out.println(context.getAgentName()+"的佣金是"+context.getTotalAmount()
                *context.getRate()*0.4);
    }
}

策略枚举
public enum CommissionEnum {

    A("a",new CommissionA()),

    B("b",new CommissionB()),

    C("c",new CommissionC());

    private CommissionStrategy strategy;

    private String name;

    // 构造方法里传入策略对象实例
    CommissionEnum(String name,CommissionStrategy strategy) {
        this.strategy = strategy;
        this.name = name;
    }

    public CommissionStrategy getStrategy() {
        return strategy;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

   
    /**
     * 根据名称获取策略(这里避免了写过多的if-else/case-when)
     * @param name
     * @return
     */
    public static CommissionStrategy getStrategy(String name) {
        for(CommissionEnum commission :CommissionEnum.values()) {
            if (commission.name.equals(name)) {
                return commission.strategy;
            }
        }
        return null;
    }
}

测试
public class Test {

    public static void main(String[] args) {
        // 初始化一个上下文,佣金的计算肯定有很多参数,有哪些策略我们可以预知
        // 但是其他参数我们没法预知,我们可以把这些参数放在上下文对象中,传递给策略
        CommissionContext context = new CommissionContext();
        context.setAgentName("中国xxx有限公司");
        context.setTotalAmount(10000);
        context.setRate(0.005);

        // 实际场景应该由外界传进来的参数,决定使用哪一种佣金算法
        CommissionStrategy strategy = CommissionEnum.getStrategy("a");

        context.getCommission(strategy);
    }
}