【设计模式】行为型设计模式之 策略模式学习实践
介绍
策略模式(Strategy),就是⼀个问题有多种解决⽅案,选择其中的⼀种使⽤,这种情况下我们
使⽤策略模式来实现灵活地选择,也能够⽅便地增加新的解决⽅案。⽐如做数学题,⼀个问题的
解法可能有多种;再⽐如商场的打折促销活动,打折⽅案也有很多种,有些商品是不参与折扣活
动要按照原价销售,有些商品打8.5折,有些打6折,有些是返现5元等。
优缺点和场景
优点
- 完美符合开闭原则,可以再不修改原系统基础上选择算法行为,或者新增新的算法。
- 策略模式,将一类算法进行了抽象,可以将公共部分进行抽离。避免重复代码。
- 策略模式对算法的封装,将算法的责任和算法本身分割开,交给不同的对象管理。提供了可替换继承关系的办法,如果不用策略模式,那么环境类,可能自己就有多个子类了,算法和算法的使用还在一起,那就不符合开闭原则。
- 可以避免多重条件选择语句。
- 算法抽离后,更方便不同的环境类复用。
缺点
- 客户端必须知道所有的策略类,并且决定使用哪一个。
- 造成了很多具体的策略的类,细小的变化都需要增加新的具体策略类。
使用场景
- 系统需要动态的在某些算法里进行选择,那么使用策略模式,用户只要维持一个算法的抽象类对象即可。
- 一个对象有很多的行为,避免在一个类里,根据不同的条件进行多重条件判断时。(if(a) 行为a if(b)行为b 将a和b拆成两个具体类。) 可以使用策略模式,将不同的行为,抽象成具体的策略类。
- 需要将具体的算法实现,和使用者进行解耦,提高算法的保密性和安全性。
结构
略模式对算法的封装,将算法的责任和算法本身分割开,交给不同的对象管理。使用算法的上下文环境类中,针对抽象的策略类进行编程。符合依赖倒转原则,并且出现了新的算法时,只需要增加一个新的实现即可。
- **策略(Strategy) **定义所有⽀持算法的公共接⼝。 Context 使⽤这个接⼝来调⽤某 ConcreteStrategy 定义的算法。
- **策略实现(ConcreteStrategy) **实现了Strategy 接⼝的具体算法
- **上下⽂环境(Context) **维护⼀个 Strategy 对象的引⽤,⽤⼀个 ConcreteStrategy 对象来装配可定义⼀个接⼝⽅法让 Strategy 访问它的数据
UML类图
基础案例
针对不同商品的打折算法,在引入策略模式前,由一个算法类的方法维护,包含大量的条件转移,并且也不利于维护。
代码下载:strategy.zip
引入策略模式前
引入策略模式前,不同的打折算法的计算过程存在的问题。
- 有多重条件选择语句,代码混乱
- 不同的算法没有办法进行在别处复用
- 新增算法的话,需要修改原来的代码,不符合开闭原则。
package behavioralPattern.strategy; import java.text.MessageFormat; /** * 引入策略模式前,不同的打折算法的计算过程 * 1.有多重条件选择语句,代码混乱 * 2.不同的算法没有办法进行在别处复用 * 3.新增算法的话,需要修改原来的代码,不符合开闭原则。 * * @author liuyp * @date 2022/09/25 */ public class BuyGoods { private String goods; private double price; private double finalPrice; private String desc; public BuyGoods(String goods, double price) { this.goods = goods; this.price = price; } public double calculate(String discountType) { if ("discount85".equals(discountType)) { finalPrice = price * 0.85; desc = "该商品可享受8.5折优惠"; } else if ("discount6".equals(discountType)) { finalPrice = price * 0.6; desc = "该商品可享受6折优惠"; } else if ("return5".equals(discountType)) { finalPrice = price >= 5 ? price - 5 : 0; desc = "该商品可返现5元"; } else { finalPrice = price; desc = "对不起,该商品不参与优惠活动"; } System.out.println(MessageFormat.format("您购买的商品为:{0},原价为: {1},{2},最终售卖价格为:{3}", goods, price, desc, finalPrice)); return finalPrice; } }引入策略模式
修改步骤
- 策略: 引入抽象类,所有的价格计算算法实现该抽象类。
- 策略实现:针对原有的if else中的价格计算算法,分别在一个个具体的策略实现类中进行实现。
- 环境类:购买商品的类中,只需要维护一个策略抽象类的引用即可,传入不通风策略实现,即可实现不同的打折策略。
抽象打折策略
/** * 策略模式中,对策略的抽象层。 * 抽象出了公共的描述、价格属性。 * 定义了需要子类实现的,具体的打折策略方法。 * * @author StoneYu * @date 2022/09/25 */ public abstract class AbstractDiscount { protected double finalPrice; protected String desc; public AbstractDiscount(String desc) { this.desc = desc; } public double getFinalPrice() { return finalPrice; } public void setFinalPrice(double finalPrice) { this.finalPrice = finalPrice; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public abstract double discount(double price); }拆分各个打折策略的实现
public class Discount6 extends AbstractDiscount { public Discount6() { super("该商品可享受6折优惠"); } @Override public double discount(double price) { finalPrice = price * 0.6; return finalPrice; } } public class Discount85 extends AbstractDiscount { public Discount85() { super("该商品可享受8.5折优惠"); } @Override public double discount(double price) { finalPrice = price * 0.85; return finalPrice; } } public class NoDiscount extends AbstractDiscount { public NoDiscount() { super("对不起,该商品不参与优惠活动"); } @Override public double discount(double price) { finalPrice = price; return finalPrice; } } public class Return5 extends AbstractDiscount { public Return5() { super("该商品可返现5元"); } @Override public double discount(double price) { this.finalPrice = price >= 5 ? price - 5 : 0; return finalPrice; } }修改环境类,只需要维护策略的引用
/** * 策略模式-环境类 * 使用策略模式优化后的购买商品的方法 * 1.没有了各种if-else * 2.不需要关注算法的具体实现,只需要维护一个策略的抽象类引用。符合依赖倒转原则 * * @author StoneYu * @date 2022/09/25 */ public class BuyGoods { private String goods; private double price; private AbstractDiscount abstractDiscount; public BuyGoods(String goods, double price, AbstractDiscount abstractDiscount) { this.goods = goods; this.price = price; this.abstractDiscount = abstractDiscount; } public double calculate() { double finalPrice = abstractDiscount.discount(this.price); String desc = abstractDiscount.getDesc(); System.out.println(MessageFormat.format("商品:{0},原价:{1},{2},最 终价格为:{3}", goods, price, desc, finalPrice)); return finalPrice; } }Spring中实践
新建策略接口
public interface DiscountStratege { /** * 折扣方法 */ void discount(); }具体的策略 1
/** * 具体策略实现1 * * @author LiuYuping * @date 2024/03/14 15:14 */ @Component public class FullReductionDiscountStratege implements DiscountStratege{ @Override public void discount() { System.out.println("满减策略,满一百减100"); } }具体策略 2
/** * 具体策略实现2 * * @author LiuYuping * @date 2024/03/14 15:15 */ @Component public class WeekDayDiscountStratege implements DiscountStratege{ @Override public void discount() { System.out.println("这里是周末满减策略"); } }策略枚举,保存所有策略名称
public enum DiscountStrategeEnum { WEEK_DAY_STRATEGE("fullReductionDiscountStratege","满一百减一百"), FULL_REDUCTION("weekDayDiscountStratege","周末满减策略"); String concernedStrategeBeanId; String strategeName; DiscountStrategeEnum(String concernedStrategeBeanId, String strategeName) { this.concernedStrategeBeanId = concernedStrategeBeanId; this.strategeName = strategeName; } public String getConcernedStrategeBeanId() { return concernedStrategeBeanId; } public String getStrategeName() { return strategeName; } }策略 Context 保存所有策略 Bean 示例
@Service public class DiscountStrategeContext { @Autowired private Map allDiscountStrategeMap; /** * 获取指定的策略 * * @param discountStrategeEnum 折扣策略枚举 * @return {@link DiscountStratege} */ public DiscountStratege getStratege(DiscountStrategeEnum discountStrategeEnum){ return allDiscountStrategeMap.get(discountStrategeEnum.getConcernedStrategeBeanId()); } }用例
在需要使用策略的地方,按需注入指定类型的策略对象,新增策略时不需要修改原有代码
@SpringBootTest class DemoApplicationTests { @Autowired DiscountStrategeContext discountStrategeContext; @Test void testDiscountStratege() { DiscountStratege stratege = discountStrategeContext.getStratege(DiscountStrategeEnum.WEEK_DAY_STRATEGE); stratege.discount(); } }
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

