策略模式

策略模式,从语义上可以看出,这种模式是针对于有多种策略的场景,

例如商场促销商品,按照消费金额,有三种优惠策略:

  1. 满100减20
  2. 满200减50
  3. 满300减100

那有的同学就说了,很简单啊,就直接 if else 判断消费金额不就完事了。当然这肯定也能满足需求,那如果后期再新增别的策略,办理会员优惠后再打折,你就不能直接判断消费金额了,你需要看当前消费者是不是会员,是会员然后看看满足哪种优惠策略,这么一套下来,你的代码可能写到最后,各种 if else 判断,可能你自己都不想去看了,而且最重要的一点是不符合开闭原则

那如果你使用策略模式,各种策略都是单独的存在,单从代码阅读性和扩展性上,会好很多

策略模式涉及到三个角色:

  1. 环境角色,持有一个策略Strategy的引用
  2. 抽象策略角色,这是一个抽象角色,通常由一个接口或抽象类实现,此角色给出所有具体策略类所需的接口
  3. 具体策略角色,包装了相关算法或行为

UML:

代码演示:

/**
 * 1、抽象优惠策略
 */
public interface DiscountsStrategy {
    /**
     * 普通优惠
     *
     * @param amount          消费金额
     * @return
     */
    Double discounts(Double amount);

    /**
     * 会员打折
     *
     * @param amount          消费金额
     * @param memberDiscounts 会员折扣
     * @return
     */
    Double discounts(Double amount, Double memberDiscounts);
}
/**
 * 2、策略实现类
 */
public class StrategyImpl implements DiscountsStrategy {
    /**
     * 普通优惠
     */
    @Override
    public Double discounts(Double amount) {
        // 子类重写
        return null;
    }

    /**
     * 会员优惠,普通优惠后再打折
     */
    @Override
    public Double discounts(Double amount, Double memberDiscounts) {
        return discounts(amount) * memberDiscounts;
    }
}
/**
 * 3、满100减20
 */
public class Strategy1 extends StrategyImpl {
    @Override
    public Double discounts(Double amount) {
        if (amount >= 100) {
            return amount - 20;
        }
        return amount;
    }
}
/**
 * 4、满200减50
 */
public class Strategy2 extends StrategyImpl {
    @Override
    public Double discounts(Double amount) {
        if (amount >= 200) {
            return amount - 50;
        }
        return amount;
    }
}
/**
 * 5、满300减100
 */
public class Strategy3 extends StrategyImpl {
    @Override
    public Double discounts(Double amount) {
        if (amount >= 300) {
            return amount - 100;
        }
        return amount;
    }
}
/**
 * 6、策略环境
 */
public class StrategyContext {
    /**
     * 抽象策略
     */
    private DiscountsStrategy strategy;
    /**
     * 消费金额
     */
    private Double amount;
    /**
     * 会员折扣
     */
    private Double memberDiscounts;

    /**
     * 会员构造函数
     * 这里可以思考一下,我还想再增加个属性,那是不是就要改,或者再新增一个构造函数?
     * 怎么规避这种繁琐的操作?当然有办法,建造者模式,下篇说这个模式
     */
    public StrategyContext(DiscountsStrategy strategy, Double amount, Double memberDiscounts) {
        this.strategy = strategy;
        this.amount = amount;
        this.memberDiscounts = memberDiscounts;
    }
    /**
     * 普通构造函数
     */
    public StrategyContext(DiscountsStrategy strategy, Double amount) {
        this.strategy = strategy;
        this.amount = amount;
    }

    /**
     * 计算优惠金额
     *
     * @return
     */
    public Double executeStrategy() {
        if (memberDiscounts != null) {
            // 会员
            return strategy.discounts(amount, memberDiscounts);
        } else {
            // 非会员
            return strategy.discounts(amount);
        }
    }
}
public class DiscountsAmount {
    public static void main(String[] args) {
        // 定义策略
        DiscountsStrategy strategy = new Strategy2();
        // 初始化策略环境
        StrategyContext context = new StrategyContext(strategy,200.0, 0.8);
        // 计算优惠后金额
        Double amount = context.executeStrategy();
        System.out.println("优惠后金额:" + amount);
    }
}

在现实生活中很少会有这种每个策略单独存在,通常会让这三种策略同时存在,然后按照消费金额,去匹配相应的优惠策略,那我们再增加一个策略,让这个策略包含上面这三种策略

/**
 * 7、
 * 满100减20
 * 满200减50
 * 满300减100
 */
public class Strategy4 extends StrategyImpl {
    @Override
    public Double discounts(Double amount) {
        if (amount >= 100 && amount < 200) {
            return new Strategy1().discounts(amount);
        } else if (amount >= 200 && amount < 300) {
            return new Strategy2().discounts(amount);
        } else if (amount > 300) {
            return new Strategy3().discounts(amount);
        }
        return amount;
    }
}
public class DiscountsAmount {
    public static void main(String[] args) {
        // 定义策略,这里只需要更换策略即可
        DiscountsStrategy strategy = new Strategy4();
        // 初始化策略环境
        StrategyContext context = new StrategyContext(strategy,200.0, 0.8);
        // 计算优惠后金额
        Double amount = context.executeStrategy();
        System.out.println("优惠后金额:" + amount);
    }
}

策略模式的优缺点

优点

1、避免了多重条件if...else if...else语句,多重条件语句并不容易维护

2、策略模式提供了管理相关算法簇的办法,恰当使用继承可以把公共代码移到父类,从而避免了代码重复

缺点

1、客户端必须知道所有的策略类,并自行决定使用 哪一个策略,这意味着客户端必须理解这些算法的区别,以便选择恰当的算法

2、如果备选策略很多,就会有很多策略类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值