策略设计模式---透彻讲解
设计模式有三种:创建型, 行为型, 结构型. 策略设计模式属于行为型. 为什么属于行为型呢? 来看看下面解释:
什么是策略呢?
举个例子: 出行方式: 可以骑自行车, 摩托车, 开小汽车, 坐公交车, 坐火车, 轮船, 飞机等等. 这些出行方式都是出行的策略.
再来看商场搞促销: 打8折, 打7折, 满100减30, 购物满500返现50等等, 无论何种打折方式, 其根本都是算法, 这些算法就是一种策略. 策略之间是可以随机互换的. 比如同一件商场,今天可以打8折, 明天可以满100件30.
策略设计模式: 定义【一组】算法, 将【每个】算法进行包装, 并且他们之间可以随意【互换】, 来看一下UML图:
从上图可以看出, 定义一个策略设计模式需要4大步骤
以上就是策略设计模式实现的4步骤
我们就以商场促销为例, 使用策略设计模式来实现.
现在商场要促销, 商品促销方式有: 原价, 折扣(8折, 7折), 满减(满100减30, 满100减20)等. 具体的促销方式就是策略.
根据实现的4个步骤, 一步一步来实现
package com.lxl.www.designPatterns.strategy; /** * 促销类 */ public interface IPromotionStrategy { /** * 促销 * * 入参是原价, 出参是促销价格 * @return */ Double promotion(PromotionVo promotionVo) throws Exception; }
这里定义了一个促销策略的接口类. 并定义了促销方案.
促销方案一共有3种: 第一种:原价, 第二种: 打折 第三种: 满减
先来看看第一种: 原价
package com.lxl.www.designPatterns.strategy; /** * 正常售卖价格 */ public class CommonPromotionStrategy implements IPromotionStrategy { @Override public Double promotion(PromotionVo promotionVo) { return promotionVo.getOriginPrice(); } }
原价也就是正常售卖的价格. 所以, 没有任何计算逻辑
第二种, 打折
package com.lxl.www.designPatterns.strategy; /** * 打折 */ public class DiscountPromotionStrategy implements IPromotionStrategy { @Override public Double promotion(PromotionVo promotionVo) throws Exception { if (promotionVo.getDiscount() < 0 || promotionVo.getDiscount() >=1 ){ throw new Exception("请输入正确的折扣"); } return promotionVo.getOriginPrice() * promotionVo.getDiscount(); } }
打折有折扣, 那么折扣必须是0-1范围, 并且最后返回折后价
第三种. 满减
package com.lxl.www.designPatterns.strategy; /** * 满减折扣 */ public class FullReductionPromotionStrategy implements IPromotionStrategy { /** * 满减 * @return * @throws Exception */ @Override public Double promotion(PromotionVo promotionVo) throws Exception { if (promotionVo.getReduction() == null || promotionVo.getFull() == null) { throw new Exception("请检查满减参数"); } Double price = promotionVo.getOriginPrice(); Double canPromotionPrice=promotionVo.getOriginPrice(); while(canPromotionPrice >= promotionVo.getFull()) { price = price - promotionVo.getReduction(); canPromotionPrice -= promotionVo.getFull(); } return price; } }
这里实现 满减逻辑是每满100减30, 要是300就减90.
我们商场里的商品到底是什么样的优惠方案呢? 有商场促销类决定
package com.lxl.www.designPatterns.strategy; import org.springframework.beans.factory.annotation.Autowired; /** * 商场促销 */ public class MallPromotion { @Autowired private IPromotionStrategy promotion; public MallPromotion(IPromotionStrategy promotion) { this.promotion = promotion; } public Double activityPromotion(PromotionVo promotionVo) throws Exception { return this.promotion.promotion(promotionVo); } }
促销类定义了一个构造函数, 用来指定当前的促销方案.
public static void main(String[] args) throws Exception { PromotionVo promotionVo = new PromotionVo(300.0, 0.8, 100.0, 30.0); System.out.println("<br><br>==========正常售卖========="); MallPromotion mallPromotionContext1 = new MallPromotion(new CommonPromotionStrategy()); System.out.println(mallPromotionContext1.activityPromotion(promotionVo)); System.out.println("<br><br>==========8折========="); MallPromotion mallPromotionContext2 = new MallPromotion(new DiscountPromotionStrategy()); System.out.println(mallPromotionContext2.activityPromotion(promotionVo)); System.out.println("<br><br>==========满100减30========="); MallPromotion mallPromotionContext3 = new MallPromotion(new FullReductionPromotionStrategy()); System.out.println(mallPromotionContext3.activityPromotion(promotionVo)); } }
我们想要什么样 促销方案都是可以的. 只需要调用商场促销类并传入促销策略即可.
一个系统有许多类,而他们之间的区别是: 行为的不同. 这时候可以使用策略设计模式.
1、一个系统, 需要动态的在几个算法之间选择, 它们之间的区别仅仅是算法或者行为的不同,那么可以使用策略模式, 这样我们可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、一个对象有很多的行为,如果不用策略设计模式,这些行为就只好使用多重条件选择语句来实现。而使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句。
如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
上面的商场促销活动. 最终策略都要暴露给客户端, 这对客户端来说不是特别友好. 我们可以结合简单工厂设计模式, 将策略进行封装.
package com.lxl.www.designPatterns.strategy; import org.springframework.beans.factory.annotation.Autowired; /** * 商场促销 */ public class MallPromotionContext { @Autowired private IPromotionStrategy promotion; public MallPromotionContext(IPromotionStrategy promotion) { this.promotion = promotion; } public MallPromotionContext(Integer type) { switch (type) { case 1: this.promotion = new CommonPromotionStrategy(); break; case 2: this.promotion = new DiscountPromotionStrategy(); break; case 3: this.promotion = new FullReductionPromotionStrategy(); break; } } public Double activityPromotion(PromotionVo promotionVo) throws Exception { return this.promotion.promotion(promotionVo); } }
这样封装以后的好处就是, 客户端只需要知道自己要什么类型的促销策略, 而不用关注具体促销策略类型.
下面来看一下策略代码的实现
public static void main(String[] args) throws Exception { PromotionVo promotionVo = new PromotionVo(300.0, 0.8, 100.0, 30.0); System.out.println("<br><br>==========正常售卖========="); MallPromotionContext mallPromotionContext1 = new MallPromotionContext(1); System.out.println(mallPromotionContext1.activityPromotion(promotionVo)); System.out.println("<br><br>==========8折========="); MallPromotionContext mallPromotionContext2 = new MallPromotionContext(2); System.out.println(mallPromotionContext2.activityPromotion(promotionVo)); System.out.println("<br><br>==========满100减30========="); MallPromotionContext mallPromotionContext3 = new MallPromotionContext(3); System.out.println(mallPromotionContext3.activityPromotion(promotionVo)); }
在基本的策略设计模式中, 选择所用具体实现的职责有客户端对象承担, 并转给策略模式的Context对象, 并没有减轻客户端需要选择判断的压力.而策略设计模式与简单工厂设计模式的结合, 选择具体实现的则在有也由Context来承担, 这就大大的减轻了客户端的职责.