策略模式
策略模式的定义是: 定义了一系列的算法, 把它们一个个的封装起来, 并且使它们可相互替换, 让算法可以独立于使用它的客户而变化.
设计原则是: 把一个类中经常改变或者将来可能会经常改变的部分提取出来作为一个接口, 然后在使用类中包含这个接口的实例, 这样使用类的对象就可以随意调用实现了这个接口的类行为.
在策略模式中有如下几个角色:
环境角色 (Context): 此角色中实现了对策略角色的引用和使用.
抽象策略角色: 此角色通常由抽象类或接口来实现, 定义了, 所以具体策略角色的行为.
具体策略角色: 此角色封装了实现不同功能的不同算法.
演示代码如下:
抽象策略类
- public interface Strategy {
- /**
- * 策略方法
- */
- void strategyMethod();
- }
具体角色类 A
- public class ConcreteStrategyA implements Strategy{
- @Override
- public void strategyMethod() {
- // 具体的行为
- }
- }
具体角色类 B
- public class ConcreteStrategyB implements Strategy {
- @Override
- public void strategyMethod() {
- // 具体的行为
- }
- }
环境角色类
- public class Context {
- /**
- * 持有一个具体的策略对象
- */
- private Strategy strategy;
- /**
- * 构造方法, 传入一个具体的策略对象
- * @param strategy 具体的策略对象
- */
- public Context(Strategy strategy)
- {
- this.strategy = strategy;
- }
- /**
- * 对外提供的使用策略的方法
- */
- public void contextMethod()
- {
- // 通常会转调具体的策略对象进行算法运算
- strategy.strategyMethod();
- }
- }
策略模式具体场景例子
某 Saas 公司的企业服务系统, 在销售时, 会根据客户的购买时长来确定优惠策略, 分为普通客户 (无优惠政策), 大客户 (98 折), 战略客户 (95 折). 普通客户是指一次性租用服务在一到 3 年之间的, 大客户指一次性使用服务 3 到 5 年之间的, 战略客户指一次性使用服务 5 年以上的. 因为每种客户价格算法不同, 所以这个场景就可以使用策略模式.
定义一个计算价格行为的接口
- public interface SalePrice {
- /**
- * 根据原价返回不同的价格
- * @param originalPrice 原始价格
- * @return
- */
- BigDecimal salePrice(BigDecimal originalPrice);
- }
然后定义三中客户的具体计算价格类 (策略类)
- public class OriginalCustomer implements SalePrice {
- /**
- * 普通客户直接返回原价
- * @param originalPrice 原始价格
- * @return 计算后的价格
- */
- @Override
- public BigDecimal salePrice(BigDecimal originalPrice) {
- return originalPrice.multiply(BigDecimal.valueOf(1));
- }
- }
- public class LargeCustomer implements SalePrice {
- /**
- * 大客户返回 98 折价格
- * @param originalPrice 原始价格
- * @return 计算后的价格
- */
- @Override
- public BigDecimal salePrice(BigDecimal originalPrice) {
- return originalPrice.multiply(BigDecimal.valueOf(0.98));
- }
- }
- public class StrategicCustomer implements SalePrice {
- /**
- * 战略客户直接返回 95 折价格
- * @param originalPrice 原始价格
- * @return 计算后的价格
- */
- @Override
- public BigDecimal salePrice(BigDecimal originalPrice) {
- return originalPrice.multiply(BigDecimal.valueOf(0.95));
- }
- }
客户类, 需要判断具体的调用哪个计算价格的方法
- public class Customer {
- private int years;
- /** 租用服务一年的初始价格 */
- private BigDecimal originalPrice = BigDecimal.valueOf(50000);
- /** 客户最终支付的价格 **/
- private BigDecimal payForPrice = BigDecimal.ZERO;
- /** 每个客户的初始价格都是原价 */
- private SalePrice salePrice = new OriginalCustomer();
- /**
- * 根据客户购买的时长来计算每一年的优惠价格 (单位: 年)
- * @param years
- */
- public void buy(int years)
- {
- this.years = years;
- payForPrice = originalPrice.multiply(BigDecimal.valueOf(years));
- // 大于 5 年的战略客户价格
- if(years>= 5){
- salePrice = new StrategicCustomer();
- }else if(years>= 3)//3 年到 5 年的大客户优惠价格
- {
- salePrice = new LargeCustomer();
- }else if(years>= 1)//1 到 3 年的普通用户原价
- {
- salePrice = new OriginalCustomer();
- }
- }
- /**
- * 计算客户最终支付的价格
- * @return
- */
- public BigDecimal payPrice(){
- return salePrice.salePrice(payForPrice);
- }
- }
客户端调用类, 自动计算支付价格
**
* 客户端调用类
- */
- @Slf4j
- public class Client {
- public static void main(String[] args){
- Customer customer = new Customer();
- customer.buy(1);
- log.info("客户需支付:{}",customer.payPrice());
- customer.buy(3);
- log.info("客户需支付:{}",customer.payPrice());
- customer.buy(6);
- log.info("客户需支付:{}",customer.payPrice());
- }
- }
输出结果:
客户需支付: 50000
客户需支付: 147000.00
客户需支付: 285000.00
根据输出结果可以看出购买不同时间的服务, 收费价格是不同的. 这样客户可以不用依赖具体的收费方法, 直接根据需要的服务的时间购买即可.
来源: https://www.cnblogs.com/jimoer/p/8899519.html