策略模式+工厂模式+模板模式彻底取代 if...else...
策略模式:一种解耦的方法,它对算法进行封装,使得算法的调用和算法本身分离。使用策略模式客户端代码不需要调整,算法之间可以互相替换,因为不同的算法实现的是同一个接口。策略模式是一种对象行为型模式。策略模式符合“开闭原则”。
策略模式包括如下角色:
-
Context :环境类
-
Strategy:抽象策略类
-
ConcreteStrategy:具体策略类
代码实现:
枚举类:
public enum SubCostTypeEnum {
GREATER0_IN_0UP(7, "原始>0,入库后>0"),
EQUAL0_OUT_0DOWN(8, "原始=0,出库后<0"),
;
private Integer value;
private String description;
private SubCostTypeEnum(Integer value, String description) {
this.value = value;
this.description = description;
}
public Integer value() {
return value;
}
public String description() {
return description;
}
public static SubCostTypeEnum valueOf(Integer value) {
for(SubCostTypeEnum type : SubCostTypeEnum.values()) {
//if(type.value() == value) {
if(type.value().equals(value)) {
return type;
}
}
return null;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class KcBook {
private BigDecimal beforeQty;
private BigDecimal beforeAmount;
private Integer direction;
private BigDecimal qty;
private BigDecimal price;
private BigDecimal afterQty;
private BigDecimal afterAmount;
}
定义策略接口:
org.springframework.beans.factory.InitializingBean#afterPropertiesSet内部实现工厂注册。用于实现环境的统一工厂。
public interface RechargeHandler extends InitializingBean {
public BigDecimal getAvgPrice(KcBook kcBook) {
System.out.println("getAvgPrice");
return new BigDecimal("0");
}
public void getRechargeName(SubCostTypeEnum subCostType) {
System.out.println("默认: " + subCostType);
}
}
实现策略工厂:
public class StrategyHandlerFactory {
private static Map<SubCostTypeEnum, CostHandler> strategyMap = new ConcurrentHashMap<>();
/**
* 根据 SubCostTypeEnum 获取对应的handler实现
*
* @param subCostType
* @return
*/
public static CostHandler getInvokeStrategyMap(SubCostTypeEnum subCostType) {
return strategyMap.get(subCostType);
}
/**
* 注册
*
* @param subCostType
* @param handler
*/
public static void register(SubCostTypeEnum subCostType, CostHandler handler) {
if (null == subCostType || null == handler) {
return;
}
strategyMap.put(subCostType, handler);
}
}
各成员实现各自的策略实现类:
@Component
public class SubCost1Handler implements CostHandler {
@Override
public void getRechargeName(SubCostTypeEnum subCostType) {
System.out.println("1: " + subCostType);
}
@Override
public void afterPropertiesSet() throws Exception {
StrategyHandlerFactory.register(SubCostTypeEnum.GREATER0_IN_0UP, this);
}
@Override
public BigDecimal getAvgPrice(KcBook kcBook) {
System.out.println("getAvgPrice");
BigDecimal tmp = kcBook.getBeforeAmount().add(kcBook.getQty().multiply(kcBook.getPrice())).divide(kcBook.getBeforeQty().add(kcBook.getQty()), 2, BigDecimal.ROUND_HALF_UP);
System.out.println("getAvgPrice:" + tmp) ;
return tmp;
}
}
如有其它新类型业务,值需要实现对应的策略即可。
test
@Test
public void test01(){
SubCostTypeEnum subCostType = null;
CostHandler costHandler = null;
subCostType = SubCostTypeEnum.GREATER0_IN_0UP;
costHandler = StrategyHandlerFactory.getInvokeStrategyMap(costType, subCostType);
System.out.println(costHandler);
KcBook kcBook = new KcBook(new BigDecimal("100"), new BigDecimal("150"), 1, new BigDecimal("2"), new BigDecimal("20"), new BigDecimal("120"), new BigDecimal("190"));
BigDecimal avg = costHandler.getAvgPrice(kcBook);
System.out.println(avg);
}
使用模板模式改造策略模式接口:
上述实现,若策略接口新增了方法,那么所有实现了改策略接口的实现类都要进行修改,对现有已完成的类改动较大,使用先将其改为模板模式。
将原有接口改造为抽象类
public abstract class CostHandler implements InitializingBean {
public void getRechargeName(SubCostTypeEnum subCostType) {
System.out.println("默认: " + subCostType);
}
public BigDecimal getAvgPrice(KcBook kcBook) {
System.out.println("getAvgPrice");
return new BigDecimal("0");
}
}
子类重新继承改抽象类即可
@Component
public class SubCost1Handler extends CostHandler {
@Override
public void getRechargeName(SubCostTypeEnum subCostType) {
System.out.println("1: " + subCostType);
}
@Override
public void afterPropertiesSet() throws Exception {
StrategyHandlerFactory.register(SubCostTypeEnum.GREATER0_IN_0UP, this);
}
@Override
public BigDecimal getAvgPrice(KcBook kcBook) {
System.out.println("getAvgPrice");
BigDecimal tmp = kcBook.getBeforeAmount().add(kcBook.getQty().multiply(kcBook.getPrice())).divide(kcBook.getBeforeQty().add(kcBook.getQty()), 2, BigDecimal.ROUND_HALF_UP);
System.out.println("getAvgPrice:" + tmp) ;
return tmp;
}
}
这样,抽象类中增加了新的方法后,已有的子类在不需要新增方法时,可以不用调整。