在日常写代码过程中,或多或少会遇到设计模式,下面对策略模式是什么及常见使用浅析一下。
策略模式用的最多就是消除 if-else、switch 等多重判断的代码,消除 if-else、switch 多重判断 可以有效应对代码的复杂性,对设计进行解耦。
如果分支判断会不断变化(增、删、改),可以在使用策略模式时满足 开闭原则(简单理解为不修改,可新增) ,就可以提高代码的扩展性。
下面为一段场景代码示例,针对该代码示例后面会应用策略模式进行重构。
public class Example {
public static void main(String[] args) {
Double discount = discount("1",10D);
System.out.println(discount);
}
private static Double discount(String type , double price) {
if (Objects.equals(type,"1")) {
return price * 0.95;
} else if (Objects.equals(type,"2")) {
return price * 0.9;
} else if (Objects.equals(type,"3")) {
return price * 0.85;
} else {
return price;
}
}
}
这段代码可以实现不同的优惠,但是若优惠的类别很多很复杂,那么这段代码的复杂性可想而知;还有可能优惠会变化,那么这段代码需要反复修改,那么会对代码功能造成巨大隐患及工作量。
应用策略模式进行重构需要如下三个步骤:
- 抽象策略接口:业务使用接口而不是具体的实现类,所以可以灵活的替换不同的策略
- 策略实现类:实现抽象策略接口,其内部封装具体的业务实现
- 策略工厂:封装创建策略实现(算法),对客户端(使用)屏蔽具体的创建细节
代码如下:
public interface DiscountStrategy {
Double discount(Double price);
}
public class Discount95Strategy implements DiscountStrategy {
@Override
public Double discount(Double price) {
return price * 0.95;
}
}
public class Discount9Strategy implements DiscountStrategy {
@Override
public Double discount(Double price) {
return price * 0.9;
}
}
public class DiscountStrategyFactory {
// 策略存储容器
private static final Map<String, DiscountStrategy> discountStrategies = new HashMap<>();
static {
discountStrategies.put("1", new Discount95Strategy());
discountStrategies.put("2", new Discount9Strategy());
}
public static DiscountStrategy chooseStrategy(String type) {
return discountStrategies.get(type);
}
}
public class Example2 {
public static void main(String[] args) {
// 从抽象策略工厂中选择具体的策略
DiscountStrategy discountStrategy = DiscountStrategyFactory.chooseStrategy("1");
// 执行具体策略
Double discount = discountStrategy.discount(10D);
// 输出策略执行结果
System.out.println("优惠后金额:" + discount);
}
}
结果如下:
优惠后金额:9.5
应用策略模式后的代码消除了if - else判断,降低了代码复杂度,但是若新增一个优惠策略,那么需要新增一个策略实现类,并且需要改动策略工厂,下面修改使之适应开闭原则(可扩展)。
将策略模式应用到spring中,在策略实现类、策略工厂中新增@Component注解,并修改策略工厂
public interface DiscountStrategy2 {
Double discount(Double price);
}
@Component
public class Discount95Strategy2 implements DiscountStrategy2 {
@Override
public Double discount(Double price) {
return price * 0.95;
}
}
@Component
public class Discount9Strategy2 implements DiscountStrategy2 {
@Override
public Double discount(Double price) {
return price * 0.9;
}
}
public class DiscountStrategyFactory2 {
private DiscountStrategy2 discountStrategy2;
public DiscountStrategyFactory2(DiscountStrategy2 discountStrategy2) {
this.discountStrategy2 = discountStrategy2;
}
public DiscountStrategy2 getDiscountStrategy2() {
return discountStrategy2;
}
public void setDiscountStrategy2(DiscountStrategy2 discountStrategy2) {
this.discountStrategy2 = discountStrategy2;
}
}
// 单元测试
@Test
public void test2() {
DiscountStrategyFactory2 discountStrategyFactory2 = new DiscountStrategyFactory2(discount95Strategy2);
DiscountStrategy2 discountStrategy2 = discountStrategyFactory2.getDiscountStrategy2();
// 执行具体策略
Double discount = discountStrategy2.discount(10D);
// 输出策略执行结果
System.out.println("优惠后金额:" + discount);
}
结果同上。通过策略模式减少代码的复杂性,继而通过 Spring 的一些特性同时满足了开闭原则,现在来了新需求只要添加新的策略类即可,健壮易扩展。
小结:策略模式核心为抽象策略接口、策略实现类、策略工厂。