比如对象的某个行为,在不同场景有不同实现方式,可以将这些行为的具体实现定义为一组策略,每个实现类实现种策略,在不同场景使用不同的实现,并且可以自由切换策略。
策略模式结构图如下:
策略模式需要一个策略接口,不同的策略实现不同的实现类,在具体业务环境中仅持有该策略接口,根据不同的场景使用不同的实现类即可。
面向接口编程,而不是面向实现。
策略模式的优点:
1、干掉繁琐的 if、switch 判断逻辑;
2、代码优雅、可复用、可读性好;
3、符合开闭原则,扩展性好、便于维护;
策略模式的缺点:
1、策略如果很多的话,会造成策略类膨胀;
2、使用者必须清楚所有的策略类及其用途;
做个例子:比如去服装店买衣服,普通会员不打折,黄金会员打9折,铂金会员打8折,钻石会员打7折,这样不同的客户价格计算方式不同,这个时候就可以使用策略模式。
/**
* @author XQ0136
* @description 账单接口
* @date 2022/6/21 11:48
*/
public interface IBill {
/**
* 计算账单
* @param money
* @return 应付金额
*/
BigDecimal calculate(BigDecimal money);
}
/**
* @author XQ0136
* @description 普通会员
* @date 2022/6/21 11:57
*/
@Service("RegularType")
public class RegularMember implements IBill{
@Override
public BigDecimal calculateBill(BigDecimal money) {
//10折
return money.multiply(new BigDecimal(1));
}
}
/**
* @author XQ0136
* @description 黄金会员
* @date 2022/6/21 11:57
*/
@Service("GoldType")
public class GoldMember implements IBill{
@Override
public BigDecimal calculateBill(BigDecimal money) {
//9折
return money.multiply(new BigDecimal(0.9)).setScale(2, RoundingMode.HALF_UP);
}
}
/**
* @author XQ0136
* @description 铂金会员
* @date 2022/6/21 11:57
*/
@Service("PlatinumType")
public class PlatinumMember implements IBill{
@Override
public BigDecimal calculateBill(BigDecimal money) {
//8折
return money.multiply(new BigDecimal(0.8)).setScale(2, RoundingMode.HALF_UP);
}
}
/**
* @author XQ0136
* @description 钻石会员
* @date 2022/6/21 11:57
*/
@Service("DiamondType")
public class DiamondMember implements IBill{
@Override
public BigDecimal calculateBill(BigDecimal money) {
//7折
return money.multiply(new BigDecimal(0.7)).setScale(2, RoundingMode.HALF_UP);
}
}
这里将Bean添加到Spring容器中管理了,不用自己去new对象,或者使用工厂模式和策略模式结合使用。
@RestController
public class IBillStrategyContext {
@Autowired
private ApplicationContext applicationContext;
/**
* 计算账单
* @param memberType
* @param money
* @return 应付金额
*/
@GetMapping("calculate")
public BigDecimal calculateBill(@RequestParam("memberType") String memberType,
@RequestParam("money") BigDecimal money){
IBill bean = applicationContext.getBean(memberType, IBill.class);
return bean.calculateBill(money);
}
}
http://localhost:10401/calculate?memberType=GoldType&money=1000
http://localhost:10401/calculate?memberType=DiamondType&money=1000
线程池的构造中有一个拒绝策略参数,默认是默认拒绝策略:
下面有几种拒绝策略的实现:
在创建线程池的时候,就可以传入不同的拒绝策略,这就是 JDK 中策略模式的经典实现了。
JDK 中大量使用了 Comparator 这个策略接口:
策略接口有了,但策略需要开发人员自己定。
集合排序我们比较熟悉的了,不同的排序规则其实就是不同的策略:
这个策略模式使用了函数式编程接口,比较规则使用匿名内部类或者 Lambda 表达式就搞定了,不需要每个规则定义一个实现类,这样就大量省略策略类了。
这个策略模式可能藏的比较深,但也是 JDK 中经典的策略模式的应用了。
策略模式:分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设定行为对象。原则就是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为算法的变化独立于算法的使用者。
参考文章:https://blog.csdn.net/youanyyou/article/details/116931663