策略(Strategy)模式:指定义一组算法,并将每个算法封装起来,运行时,可以灵活选择其中的某个算法
优点:
- 策略模式可以有效避免多重if语句
- 策略模式可以提供相同行为的不同实现
缺点:
- 调用方必须了解不同策略算法的区别,以便于在需要时调用
- 容易造成过多策略类,维护难度提高
策略模式在Java标准库有着广泛的使用,以排序为例,可以看看通过Array.sort()
方法实现忽略大小写排序
public static void main(String[] args) {
String[] arr = {"c","C","Z","a"};
Arrays.sort(arr,String::compareToIgnoreCase);
System.out.println(Arrays.toString(arr)); // [a, c, C, Z]
}
如果想要倒序排序则可以修改为:Arrays._sort_(arr,(s1,s2)-> s1.compareTo(s2))
,如果想要忽悠大小写排序则可以使用:Arrays.sort(arr,String::compareToIgnoreCase);
而这两种算法,即是策略
上面的示例中使用到了策略模式,不难看出,策略模式的特点是:它的流程是确定的,但是某些算法依赖调用方传入的策略,不同的策略,实现了不同的结果,从而增强了系统的灵活性
示例:
一个完整的策略模式,要定义策略以及使用策略的上下文。以购物车结算为例,假设网站有普通用户,vip会员和超级vip会员,不同的用户享受的折扣不相同。
�首先定义一个打折策略接口
// 折扣策略接口
interface DiscountStrategy{
// 计算折扣
BigDecimal getDiscount(BigDecimal total);
}
同时有各种策略的实现
// 普通用户策略
static class GeneralUser implements DiscountStrategy{
@Override
public BigDecimal getDiscount(BigDecimal total) {
// 普通用户不享受折扣
return total;
}
}
// vip用户策略
static class VipUser implements DiscountStrategy{
@Override
public BigDecimal getDiscount(BigDecimal total) {
// vip用户享受8折优惠
return total.multiply(new BigDecimal("0.2")).setScale(2, RoundingMode.DOWN);
}
}
// 超级vip用户策略
static class SuperVipUser implements DiscountStrategy{
@Override
public BigDecimal getDiscount(BigDecimal total) {
// 超级vip用户享受6折优惠
return total.multiply(new BigDecimal("0.4")).setScale(2, RoundingMode.DOWN);
}
}
然后,需要一个可以使用策略的地方
// 应用策略
static class DiscountContext{
// 默认策略为普通用户类型
private DiscountStrategy strategy = new GeneralUser();
// 可以设置用户类型
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
// 计算折扣
public BigDecimal calculatePrice(BigDecimal total){
return total.subtract(this.strategy.getDiscount(total)).setScale(2,RoundingMode.CEILING);
}
}
测试
public static void main(String[] args) {
DiscountContext context = new DiscountContext();
// 普通用户无折扣
BigDecimal price1 = context.calculatePrice(BigDecimal.valueOf(100));
System.out.println(price1); // 100
// vip用户8折优惠
context.setStrategy(new VipUser());
BigDecimal price2 = context.calculatePrice(BigDecimal.valueOf(100));
System.out.println(price2); // 80
// 超级VIP6折优惠
context.setStrategy(new SuperVipUser());
BigDecimal price3 = context.calculatePrice(BigDecimal.valueOf(100));
System.out.println(price3); // 60
}