策略模式:Strategy,是指,定义一组算法,并把其封装到一个对象中。然后在运行时,可以灵活的使用其中的一个算法。以下记录我对策略模式的理解(部分解释借鉴自廖雪峰老师)
策略模式是为了允许调用方选择一个算法,从而通过不同策略实现不同的计算结果。体现了模块化的思想,不必为了一点小改动而造成程序整体的修改,方便使用者选择不同方案。通过扩展策略,不必修改主逻辑,即可获得新策略的结果。
一个完整的策略模式要定义策略以及使用策略的上下文。我们以网购图书为例,假设网站针对普通顾客、会员有不同的折扣,同时活动期间还有一个满100减20的活动,这些就可以作为策略实现。
先定义打折策略接口:
public interface DiscountStrategy {
// 计算折扣额度:
BigDecimal getDiscount(BigDecimal total);
}
策略示意图如下,共有三种打折策略
┌───────────────┐ ┌─────────────────┐
│DiscountContext│─ ─ ─>│DiscountStrategy │
└───────────────┘ └─────────────────┘
▲
│ ┌─────────────────────┐
├─│CommonUserStrategy │
│ └─────────────────────┘
│ ┌─────────────────────┐
├─VIPStrategy│
│ └─────────────────────┘
│ ┌─────────────────────┐
└─│SpecialStrategy │
└─────────────────────┘
要应用策略,需要建立上下文部分
public class DiscountContext {
// 持有某个策略:
private DiscountStrategy strategy = new UserDiscountStrategy();
// 允许客户端设置新策略:
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public BigDecimal calculatePrice(BigDecimal total) {
return total.subtract(this.strategy.getDiscount(total)).setScale(2);
}
}
接下来,就是三种可供选择的策略。
1.普通顾客和会员的策略:
public class UserDiscountStrategy implements DiscountStrategy {
public BigDecimal getDiscount(BigDecimal total) {
// 普通会员打九折:
return total.multiply(new BigDecimal("0.1")).setScale(2, RoundingMode.DOWN);
}
}
活动期间促销策略如下
public class OverDiscountStrategy implements DiscountStrategy {
public BigDecimal getDiscount(BigDecimal total) {
// 满100减20优惠:
return total.compareTo(BigDecimal.valueOf(100)) >= 0 ? BigDecimal.valueOf(20) : BigDecimal.ZERO;
}
}
调用方必须首先创建一个DiscountContext,并指定一个策略(或者使用默认策略),即可获得折扣后的价格:
DiscountContext discount = new DiscountContext();
// 默认策略(普通用户)折扣:
BigDecimal count1 = discount.calculatePrice(BigDecimal.valueOf(120));
System.out.println(count1);
// 活动折扣:
discount.setStrategy(new OverDiscountStrategy());
BigDecimal count2 = discount.calculatePrice(BigDecimal.valueOf(120));
System.out.println(count2);
// 会员折扣:
discount.setStrategy(new PrimeDiscountStrategy());
BigDecimal count3 =discount.calculatePrice(BigDecimal.valueOf(120));
System.out.println(count3);