项目里有一个关于计算佣金的需求,之前已经有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);
}
}