策略模式
策略模式是一种行为设计模式,是23种软件设计模式之一,它允许在运行时选择算法的行为。通过定义一系列的算法,将它们各自封装成策略(Strategy)类,并使它们可以互相替换,策略模式让算法独立于使用它们的客户端而变化,从而能够方便地切换算法或策略。
一.不使用策略模式
Cost实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Cost {
private Integer unitPrice;
private int type;
}
计算运费service类
@Service
public class ExpressServiceImpl implements ExpressService {
private static Cost JD = new Cost(8, 1);//京东的单价是8元,类型是1
private static Cost SF = new Cost(9, 2);//顺丰的单价是9元,类型是2
private static Cost YT = new Cost(6, 2);//圆通的单价是9元,类型是2
@Override
public Integer calculateCost(int type, int distance) {
// 运费=距离*单价
if (type == JD.getType()) {
return JD.getUnitPrice() * distance;
} else if (type == SF.getType()) {
return SF.getUnitPrice() * distance;
} else if (type == YT.getType()) {
return YT.getUnitPrice() * distance;
} else {
return -1;
}
}
}
如果是通过以上实现该功能,每次新增快递公司都需要新增一条else-if
语句,需要修改到原代码,不符合开闭原则
二.使用策略模式
1.新增策略接口
public interface ExpressStrategy {
int calculateCost(int distance);
}
2.新增具体策略实现类
京东策略实现类
public class JDExpressStrategy implements ExpressStrategy {
//设置单价
private static final int UNIT_PRICE=8;
@Override
public int calculateCost(int distance) {
return UNIT_PRICE * distance;
}
}
顺丰策略实现类
public class SFExpressStrategy implements ExpressStrategy {
private static final int UNIT_PRICE = 9;
@Override
public int calculateCost(int distance) {
return UNIT_PRICE * distance;
}
}
圆通策略实现类
public class YTExpressStrategy implements ExpressStrategy {
private static final int UNIT_PRICE = 6;
@Override
public int calculateCost(int distance) {
return UNIT_PRICE * distance;
}
}
3.新增枚举类
供业务方法注入使用, 也可以使用Map类型、集合或者常量类等多种注入方式, 根据实际需求和个人习惯
public enum ExpressTypeEnum {
JD(1, new JDExpressStrategy()),
SF(2, new SFExpressStrategy()),
YT(3, new YTExpressStrategy());
private final int type;
private final ExpressStrategy strategy;
ExpressTypeEnum(int type, ExpressStrategy strategy) {
this.type = type;
this.strategy = strategy;
}
public int getType() {
return type;
}
public ExpressStrategy getStrategy() {
return strategy;
}
public static ExpressStrategy getStrategyByType(int type) {
for (ExpressTypeEnum expressType : values()) {
if (expressType.getType() == type) {
return expressType.getStrategy();
}
}
return null;
}
}
4.业务注入并使用策略模式
@Service
public class ExpressServiceImpl_Strategy implements ExpressService {
@Override
public Integer calculateCost(int type, int distance) {
ExpressStrategy strategy = ExpressTypeEnum.getStrategyByType(type);
if (strategy == null) {
return -1;
}
return strategy.calculateCost(distance);
}
}
三.为什么要使用策略模式
使用策略模式可以避免许多的条件语句(多个if-else if-else或switch-case),使得代码更加清晰。通过策略模式,可以把具体的算法和客户端的使用代码可以被分离开,提高了算法的重用性和灵活性。增加条件时只需增加策略实现类,无需修改原本的代码,符合开闭原则。
在以上例子中,想增加快递公司,只需要新增快递公司的策略实现类,和在枚举类中新增对应的枚举,不必修改任何业务逻辑层面的代码。
建议在面对多层 if-else 结构(大于三层)并且每层包含的业务逻辑代码较为复杂(超过三行)时,考虑实施策略模式以优化代码结构和维护性。例子中看起来使用if-else判断更方便是因为我为了方便理解, 把业务写的很简单.