这是我参与 8 月更文挑战的第3天,活动详情查看: 8月更文挑战
概念
定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。
关键点:定义、创建、使用
- 定义策略接口,算法,一组实现该接口的策略类;
- 策略的创建由工厂来完成,封装创建策略的细节;
- 策略选择使用有两种方式:
- 一种是静态确定,直接new 相应的策略接口;
- 一种是动态确定,根据运行参数动态实例化策略接口;
下面以不同的优惠策略来实现策略模式。
策略定义
1. 定义策略接口
/**
* 策略接口
*/
public interface Strategy {
/**
* 优惠算法
*/
Object discount();
}
复制代码
2. 定义一组实现接口的策略类
- 打折策略类
public class DiscountStrategy implements Strategy {
@Override
public Object discount() {
System.out.println("打折");
return null;
}
}
复制代码
- 减价策略类
public class ReducePriceStrategy implements Strategy {
@Override
public Object discount() {
System.out.println("减价");
return null;
}
}
复制代码
- 赠送优惠券策略类
public class FreeProductStrategy implements Strategy {
@Override
public Object discount() {
System.out.println("赠送产品");
return null;
}
}
复制代码
策略工厂
1. 策略枚举类型
public enum DiscountEnum {
DISCOUNT, /** 打折 **/
REDUCE_PRICE, /** 减价 **/
FREE_COUPON, /** 赠送优惠券 **/
FREE_PRODUCT; /** 赠送产品 **/
}
复制代码
2. 策略工厂
2.1 无状态的策略工厂
当具体的优惠算法中是无状态的,那么可以用map将类型和策略相对应,在获取具体实现策略时通过 “查表法” 即可获取到相应的策略实现。
/**
* 无状态的策略工厂
* 无状态指的是纯算法,不需要每次调用都创建一个新的Strategy
*/
public class StrategyFactory {
private static final Map<DiscountEnum,Strategy> strategies = new HashMap<>();
static {
strategies.put(DiscountEnum.DISCOUNT,new DiscountStrategy());
strategies.put(DiscountEnum.REDUCE_PRICE,new ReducePriceStrategy());
strategies.put(DiscountEnum.FREE_COUPON,new FreeCouponStrategy());
strategies.put(DiscountEnum.FREE_PRODUCT,new FreeProductStrategy());
}
/**
* 获取具体的实现策略
* @param discountEnum
* @return
*/
public static Strategy getStrategy(DiscountEnum discountEnum) {
if(discountEnum == null) {
throw new IllegalArgumentException("discountNum should not be null");
}
return strategies.get(discountEnum);
}
}
复制代码
2.2 有状态的策略工厂
当策略算法是有状态的,那么就需要在每次获取策略时重新创建策略类。可以通过反射的方式动态实例化出对象,使用map存储类型与策略Class的关系、或者通过注解动态创建。
这里使用map存储,一样通过map查表法创建;
/**
* 有状态的策略工厂
*/
public class StrategyFactory2 {
private static final Map<DiscountEnum,Class<? extends Strategy>> strategies = new HashMap<>();
static {
strategies.put(DiscountEnum.DISCOUNT, DiscountStrategy.class);
strategies.put(DiscountEnum.REDUCE_PRICE, ReducePriceStrategy.class);
strategies.put(DiscountEnum.FREE_COUPON, FreeCouponStrategy.class);
strategies.put(DiscountEnum.FREE_PRODUCT, FreeProductStrategy.class);
}
/**
* 每一次获取都重新创建一个 Strategy
*/
public static Strategy getStrategy(DiscountEnum discountEnum) throws InstantiationException, IllegalAccessException {
if(discountEnum == null) {
throw new IllegalArgumentException("discountNum should not be null");
}
Class<? extends Strategy> strategyClass = strategies.get(discountEnum);
return strategyClass.newInstance();
}
}
复制代码
策略的使用
- 运行时动态创建
/**
* 运行时动态确定
*/
@Test
public void testStrategy() {
// 假设动态运行时获取的类型为减价类型
DiscountEnum discountEnum = DiscountEnum.REDUCE_PRICE;
Strategy strategy = StrategyFactory.getStrategy(discountEnum);
strategy.discount();
}
复制代码
- 静态创建
/***
* 静态确定策略
*/
@Test
public void testStrategy4Static() {
// 假设知道要使用的算法为减价,直接new对应的策略实例
Strategy strategy = new DiscountStrategy();
strategy.discount();
}
复制代码
总结
从上面的过程中可以发现,策略模式实际上就是定义算法接口 + 工厂模式的组合,通过定义算法接口规定算法签名,利用查表法在策略集合中找到符合条件的策略,从而实现不同策略的切换。从表现上看是抽离了if-else 的逻辑,实际上更多的作用是解耦了策略的定义、创建以及使用,使每个部分不至于过于复杂,从而最小化、集中化的管理代码。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END