如何去使用策略模式去避免 if/else呢?

模板模式,为了起到一个代码复用和扩展的能力,何其类似的回调亦是如此

那么,策略模式,就是为了避免冗长的if-else或者switch判断.以及提供扩展点

策略模式在定义中是指,定义一组算法类,然后将不同的算法彼此隔离,彼此可以进行互相替换,策略模式可以让算法的变化独立于使用的客户端

工厂模式是解耦对象的创建和使用,观察者模式是解耦观察者和被观察者,策略模式和两者相似,起到一个解耦的作用,不过,其解耦出了三个部分 策略的定义 创建和使用

1.策略模式的定义

定义比较简单,一个策略接口和一个实现这个接口的策略类

利用面向对象的多态的特性,方便用户去灵活的替换不同的策略实现类

public interface Strategy {

void algorithmInterface();

}

public class ConcreteStrategyA implements Strategy {

@Override

public void  algorithmInterface() {

//具体的算法…

}

}

public class ConcreteStrategyB implements Strategy {

@Override

public void  algorithmInterface() {

//具体的算法…

}

}

2.策略的创建,必然不能每次都去new一个新的策略类,而是可以选择去使用工厂模式或者使用一个框架去方便注入

那么,使用的方式可以如下

public class StrategyFactory {

private static final Map<String, Strategy> strategies = new HashMap<>();

static {

strategies.put(“A”, new ConcreteStrategyA());

strategies.put(“B”, new ConcreteStrategyB());

}

public static Strategy getStrategy(String type) {

if (type == null || type.isEmpty()) {

throw new IllegalArgumentException(“type should not be empty.”);

}

return strategies.get(type);

}

}

一般来说,策略类都是一个无状态的工具,这种策略类是可以被共享使用的,不需要每次调用get的时候,去创建一个新的,那么上面的方式就很合适,事先创建好每一个策略对象,然后放在一个集合存储起来,使用的时候直接调用

如果每次都需要创建新的策略类,还是必须去进行判断,利用多次If-else,比如如下

public class StrategyFactory {

public static Strategy getStrategy(String type) {

if (type == null || type.isEmpty()) {

throw new IllegalArgumentException(“type should not be empty.”);

}

if (type.equals(“A”)) {

return new ConcreteStrategyA();

} else if (type.equals(“B”)) {

return new ConcreteStrategyB();

}

return null;

}

}

3.策略的使用

策略模式是去包含一组可选择的策略,那么如何确定使用哪个策略呢?

可以分为两种方式,分别是运行时指定和非运行时指定

运行时动态分配是指的策略,也就是在程序运行的期间,根据配置 用户输入,计算结果这些不确定因素,然后确定使用的类型

// 策略接口:EvictionStrategy

// 策略类:LruEvictionStrategy、FifoEvictionStrategy、LfuEvictionStrategy…

// 策略工厂:EvictionStrategyFactory

public class UserCache {

private Map<String, User> cacheData = new HashMap<>();

private EvictionStrategy eviction;

public UserCache(EvictionStrategy eviction) {

this.eviction = eviction;

}

//…

}

// 运行时动态确定,根据配置文件的配置决定使用哪种策略

public class Application {

public static void main(String[] args) throws Exception {

EvictionStrategy evictionStrategy = null;

Properties props = new Properties();

props.load(new FileInputStream(“./config.properties”));

String type = props.getProperty(“eviction_type”);

evictionStrategy = EvictionStrategyFactory.getEvictionStrategy(type);

UserCache userCache = new UserCache(evictionStrategy);

//…

}

}

// 非运行时动态确定,在代码中指定使用哪种策略

public class Application {

public static void main(String[] args) {

//…

EvictionStrategy evictionStrategy = new LruEvictionStrategy();

UserCache userCache = new UserCache(evictionStrategy);

//…

}

}

上面代码中,说明了非运行时确定,也就是第二个Application中的使用方式,并不能发挥策略模式的优势,直接先在代码中指定了使用的类型,让策略模式毫无用处

其实说到底,策略模式的主要目的,是为了避免过多的代码判断逻辑,但也并非是完全消除了,很多情况下只是放在了策略工厂类中进行判断罢了

就跟如下的场景一样

public class OrderService {

public double discount(Order order) {

double discount = 0.0;

OrderType type = order.getType();

if (type.equals(OrderType.NORMAL)) { // 普通订单

//…省略折扣计算算法代码

} else if (type.equals(OrderType.GROUPON)) { // 团购订单

//…省略折扣计算算法代码

} else if (type.equals(OrderType.PROMOTION)) { // 促销订单

//…省略折扣计算算法代码

}

return discount;

}

}

如何移除这段代码的分支判断逻辑呢?

可以将这个订单类型改为多个策略类,然后在一个工厂策略类中进行这些策略类,并且由ordertype来进行判断选择哪个策略

// 策略的定义

public interface DiscountStrategy {

double calDiscount(Order order);

}

// 省略NormalDiscountStrategy、GrouponDiscountStrategy、PromotionDiscountStrategy类代码…

// 策略的创建

public class DiscountStrategyFactory {

private static final Map<OrderType, DiscountStrategy> strategies = new HashMap<>();

static {

strategies.put(OrderType.NORMAL, new NormalDiscountStrategy());

strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());

strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());

}

public static DiscountStrategy getDiscountStrategy(OrderType type) {

return strategies.get(type);

}

}

// 策略的使用

public class OrderService {

public double discount(Order order) {

OrderType type = order.getType();

DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type);

return discountStrategy.calDiscount(order);

}

}

这样我们利用了Map,来进行查找,并且利用type,从Map中获取到对应的策略,从而避免了if-else的判断

同样,如果需要创建不停的策略对象,使用其他的工厂类实现方式就行了,具体的代码如下

那么这一章的重点就很简单了

public class DiscountStrategyFactory {

public static DiscountStrategy getDiscountStrategy(OrderType type) {

if (type == null) {

throw new IllegalArgumentException(“Type should not be null.”);

}

if (type.equals(OrderType.NORMAL)) {

return new NormalDiscountStrategy();

} else if (type.equals(OrderType.GROUPON)) {

return new GrouponDiscountStrategy();

} else if (type.equals(OrderType.PROMOTION)) {

return new PromotionDiscountStrategy();

}

return null;

}

}

策略模式定义一族算法类,每个算法分别封装起来,可以彼此替换,策略模式让其算法变化独立于客户端

策略模式由三部分组成,定义策略,创建策略,使用策略类

策略的定义不必说,很简单,只需要包含一个策略接口和一组实现策略类

策略的创建交给工厂类完成,封装具体实现

策略模式使用时候有编译时候确定和运行时确定,一般是运行时确定

发表评论

邮箱地址不会被公开。 必填项已用*标注