策略模式 桃扇骨 2021-09-22 23:22 260阅读 0赞 ** 策略模式**(Strategy):定义了一系列算法家族,将每种算法分别封装起来,使得各种算法之间可以互相替换。策略模式可以让算法的变化不影响使用算法的客户,符合**开放-封闭原则**(OCP,Open Closed Principle)。 策略模式举例比较多的就是商场打折优惠(原价、打八折、满99减50等)和用户折扣策略(普通用户、白金用户、钻石王老五等)。我们就以商场打折优惠来看一下策略模式的使用: 不考虑代码设计的情况,一般会写出如下代码: package com.dcc.openTalk.designPattern.strategyPattern.noDesignPattern; /** * 场景:商场打折优惠 * 原价、打八折、满99减50 * 普通实现如下 * * @author dxc * @date 2019/3/30 */ public class MarketDiscount { /** * 计算实付金额 * * @param totalPrice 商品总额 * @param discountType 打折类型 * @return */ public static double calculateActualAmount(double totalPrice, int discountType) { switch (discountType){ //原价 case 0: break; //打八折 case 1: totalPrice = totalPrice * 0.8; break; //满99减50 case 2: if (totalPrice >= 99) { totalPrice = totalPrice - 50; } break; default: } return totalPrice; } public static void main(String []args){ System.out.println(calculateActualAmount(2019.00, 0)); System.out.println(calculateActualAmount(2019.00, 1)); System.out.println(calculateActualAmount(2019.00, 2)); } } 当新增加了一种优惠方式,比如半价销售时,可能需要增加case 分支,这就违反了开放封闭原则。 改用策略模式设计之后是这样的: 优惠策略接口: package com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern; /** * @author dxc * @date 2019/3/31 */ public interface DiscountStrategy { /** * 计算实付金额 * * @param totalPrice 商品总额 * @return */ double calculateActualAmount(double totalPrice); } 优惠策略A对应原价出售: package com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern; /** * 原价处理 * * @author dxc * @date 2019/3/31 */ public class DiscountStrategyA implements DiscountStrategy { public double calculateActualAmount(double totalPrice) { return totalPrice; } } 优惠策略B对应打八折出售: package com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern; /** * 打八折优惠策略 * * @author dxc * @date 2019/3/31 */ public class DiscountStrategyB implements DiscountStrategy { public double calculateActualAmount(double totalPrice) { return 0.8 * totalPrice; } } 优惠策略C对应满99减50: package com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern; /** * 满99减50 * * @author dxc * @date 2019/3/31 */ public class DiscountStrategyC implements DiscountStrategy{ public double calculateActualAmount(double totalPrice) { if (totalPrice >= 99) { totalPrice = totalPrice - 50; } return totalPrice; } } 策略上下文,维护一个对策略对象的引用: package com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern; /** * 策略上下文 * @author dxc * @date 2019/3/31 */ public class StrategyContext { private DiscountStrategy discountStrategy; public StrategyContext(DiscountStrategy discountStrategy){ this.discountStrategy = discountStrategy; } public double getActualPrice(double totalPrice){ return discountStrategy.calculateActualAmount(totalPrice); } } 客户端调用类: package com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern; /** * 客户端调用 * @author dxc * @date 2019/3/31 */ public class Client { public static void main(String []args){ StrategyContext context = new StrategyContext(new DiscountStrategyB()); double actualPrice = context.getActualPrice(2019.00); System.out.println("优惠后实付:" + actualPrice); } } 写到这里基本上,就是策略模式的大致结构了。细心的读者可能会发现,上面的Client类代码中需要客户端自己根据所属的优惠类型去选择实例化哪种优惠策略,是否可以把这部分逻辑放到服务方呢。这当然是可以的,真正在项目中使用时,客户端只要告诉服务端当前优惠类型就可以了,具体使用哪种策略由服务方来匹配并给出结果,可以通过配置(xml配置文件或者注解配置)。也有利用反射结合策略模式的。 我们以在SpringBoot的项目中为例,介绍配置方式的实现: 三种策略bean: /** * 原价处理 * * @author dxc * @date 2019/3/31 */ @Service("discountStrategyA") public class DiscountStrategyA implements DiscountStrategy { public double calculateActualAmount(double totalPrice) { return totalPrice; } } /** * 打八折优惠策略 * * @author dxc * @date 2019/3/31 */ @Service("discountStrategyB") public class DiscountStrategyB implements DiscountStrategy { public double calculateActualAmount(double totalPrice) { return 0.8 * totalPrice; } } package com.dcc.openTalk.designPattern.strategyPattern.springProject; import com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern.DiscountStrategy; import org.springframework.stereotype.Service; /** * 满99减50 * * @author dxc * @date 2019/3/31 */ @Service("discountStrategyC") public class DiscountStrategyC implements DiscountStrategy{ public double calculateActualAmount(double totalPrice) { if (totalPrice >= 99) { totalPrice = totalPrice - 50; } return totalPrice; } } 在策略上下文中使用map存储打折类型和打折具体策略类: package com.dcc.openTalk.designPattern.strategyPattern.springProject; import com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern.DiscountStrategy; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Map; /** * 策略上下文 * @author dxc * @date 2019/3/31 */ @Component("strategyContext") public class StrategyContext { @Resource(name = "discountStrategyMap") private Map<Integer,DiscountStrategy> discountStrategyMap; public double doAction(int type, double totalPrice) { return this.discountStrategyMap.get(type).calculateActualAmount(totalPrice); } } 配置类: package com.dcc.openTalk.designPattern.strategyPattern.springProject; import com.dcc.openTalk.designPattern.strategyPattern.useDesignPattern.DiscountStrategy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @author dxc * @date 2019/4/15 0015 */ @Configuration public class Config { @Autowired private DiscountStrategyA discountStrategyA; @Autowired private DiscountStrategyB discountStrategyB; @Autowired private DiscountStrategyC discountStrategyC; @Bean public Map<Integer, DiscountStrategy> discountStrategyMap(){ Map<Integer, DiscountStrategy> map = new HashMap<>(); map.put(1, discountStrategyA); map.put(2, discountStrategyB); map.put(3, discountStrategyC); return map; } } 测试类: package com.dcc.openTalk.designPattern.strategyPattern.springProject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @author dxc * @date 2019/4/15 0015 */ @RestController @RequestMapping("/strategyPattern") public class TestController { @Autowired private StrategyContext strategyContext; @GetMapping("/test") public double calculateActualAmount(@RequestParam(name = "totalPrice") double totalPrice, @RequestParam(name = "type") int type){ return strategyContext.doAction(type, totalPrice); } } 本地启动SpringBoot项目,测试如下: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDc2MzQ1_size_16_color_FFFFFF_t_70][] 代码地址:[https://github.com/WhiteBookMan1994/OpenTalk/tree/master/designPattern][https_github.com_WhiteBookMan1994_OpenTalk_tree_master_designPattern] [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDc2MzQ1_size_16_color_FFFFFF_t_70]: /images/20210920/2ee34a74985a42a88b993463e5642b8a.png [https_github.com_WhiteBookMan1994_OpenTalk_tree_master_designPattern]: https://github.com/WhiteBookMan1994/OpenTalk/tree/master/designPattern
相关 策略模式 1. 定义 > 定义一系列算法,把他们一个个封装起来,并且使他们可以互相替换。本模式使得算法 > 可以独立于使用它的客户而变化。 2. 策略模式的结构 ![策 川长思鸟来/ 2022年05月29日 04:09/ 0 赞/ 46 阅读
相关 策略模式 前言 1、面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同的属性和功能的对象的抽象集合才是类。 2、简单工厂也能解决问题,但是 港控/mmm°/ 2021年12月08日 16:21/ 0 赞/ 307 阅读
相关 策略模式 用了也不知道用了的典型。 就是接口存在的意义,意图和实现分离。 就好像1+1=2,实现了一个简单加法一样。。。 转载于:https://www.cnblogs.com/l 曾经终败给现在/ 2021年11月27日 06:14/ 0 赞/ 292 阅读
相关 策略模式 策略模式 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式中,我们创建表示各种策略 亦凉/ 2021年09月29日 15:56/ 0 赞/ 280 阅读
相关 策略模式 策略模式(Strategy):定义了一系列算法家族,将每种算法分别封装起来,使得各种算法之间可以互相替换。策略模式可以让算法的变化不影响使用算法的客户,符合开放- 桃扇骨/ 2021年09月22日 23:22/ 0 赞/ 261 阅读
相关 策略模式 13.策略模式 class Program { static void Main(string[] args) 本是古典 何须时尚/ 2021年09月17日 00:00/ 0 赞/ 392 阅读
相关 策略模式 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式中,我们创建表示各种策略的对象和一个行为 忘是亡心i/ 2021年09月16日 23:00/ 0 赞/ 431 阅读
相关 策略模式 策略模式 1. 模式动机 2. 模式定义 3. 模式结构 4. 时序图 5. 代码分析 6. 模式分析 7. 优点 8. 深碍√TFBOYSˉ_/ 2021年08月31日 02:47/ 0 赞/ 530 阅读
相关 策略模式 面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。 策略模式:定义了算法家族,分别封装起来,让它们之间... 灰太狼/ 2020年11月29日 04:23/ 0 赞/ 600 阅读
还没有评论,来说两句吧...