浅谈Strategy策略模式
一、前言
什么是策略模式?
策略这个词应该怎么理解呢,打个比方说,我们出门的时候选择不同的出行方式,比如步行、骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。
再比如我们去逛商场,商场现在正在搞活动,有打折的、满减的、返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身就是一种策略,并且这些算法是随时可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。
策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。
二、策略模式的应用
1、何时使用
对于业务开发来说,业务逻辑的复杂是必然的,随着业务发展,需求只会越来越复杂,为了考虑到各种各样的情况,代码中不可避免的会出现很多if-else。
一旦代码中if-else过多,就会大大的影响其可读性和可维护性,而且代码显得很low。
策略模式完美的解决了ifelse的烦恼!
2、方法
将这些算法封装成一个一个的类,任意的替换
3、优点
- 算法可以自由切换
- 避免使用多重条件判断
- 扩展性良好,增加一个策略只需实现接口即可
4、缺点
- 策略类数量会增多,每个策略都是一个类,复用性很小
- 所有的策略类都需要对外暴露
5、应用实例
- 出行方式,自行车、汽车等,每一种出行方式都是一个策略
- 商场促销方式,打折、满减等
- java AWT中 LayoutManager ,即布局管理器
6、注意事项
如果一个系统的策略多于四个,就需要考虑使用混合模式解决策略类膨胀的问题
三、策略模式的实现
下面就以商场促销为例使用策略模式实现商场促销算法。UML图如下:
1、上下文类
首先声明一个 CashSuper 对象,通过构造方法,传入具体的收费策略, getResult() 方法的功能为根据收费策略的不同获取计算结果。
package designMode.strategy; public class CashContext { private CashSuper cashSuper; public CashContext(CashSuper cashSuper) { this.cashSuper = cashSuper; } public double getResult(double money){ return cashSuper.acceptCash(money); } }
2、现金收费抽象类
策略类,为抽象类,抽象出收费的方法供子类实现。
package designMode.strategy; public abstract class CashSuper { public abstract double acceptCash(double money); }
3、正常收费子类
package designMode.strategy; public class CashNormal extends CashSuper { @Override public double acceptCash(double money) { return money; } }
4、打折收费子类
package designMode.strategy; public class CashRebate extends CashSuper { private double moneyRebate = 0.8; public CashRebate(double moneyRebate) { this.moneyRebate = moneyRebate; } @Override public double acceptCash(double money) { return money*moneyRebate; } }
5、返利收费子类
package designMode.strategy; public class CashReturn extends CashSuper { private double moneyConditation = 0.0; private double moneyReturn = 0.0d; public CashReturn(double moneyConditation, double moneyReturn) { this.moneyConditation = moneyConditation; this.moneyReturn = moneyReturn; } @Override public double acceptCash(double money) { double result = money; if(money>moneyConditation){ result = money-Math.floor(money/moneyConditation)*moneyReturn; } return result; } }
6、client客户端
package designMode.strategy; import java.util.Scanner; public class Client { public static void main(String[] args) { CashContext cashContext = null; Scanner scanner = new Scanner(System.in); System.out.println("请输入打折方式(1/2/3):"); int in = scanner.nextInt(); String type = ""; switch (in){ case 1: cashContext = new CashContext(new CashNormal()); type += "正常收费"; break; case 2: cashContext = new CashContext(new CashReturn(300,100)); type +="满300返100"; break; case 3: cashContext = new CashContext(new CashRebate(0.8)); type += "打八折"; break; default: System.out.println("请输入1/2/3"); break; } double totalPrices = 0; System.out.print("请输入单价:"); double price = scanner.nextDouble(); System.out.println("请输入数量:"); double num = scanner.nextDouble(); totalPrices = cashContext.getResult(price * num); System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrices); scanner.close(); } }
7、运行结果
四、策略模式与工程模式的区别
1、策略模式是行为性模式,适应行为的变化 ,强调父类的调用子类的特性 。
工厂模式是创建型模式,适应对象的变化,强调统一接口 。
2、策略模式封装行为,调用的时候必须先制定实例化具体的类,再调用抽象的方法; 策略模式的作用是让一个对象在许多行为中选择一种行为。
工厂模式封装对象,实例化对象后调用的时候要知道具体的方法。
3、策略模式是调用不同类方法, 工厂模式是对父类进行重写。
这俩个模式本来就是解决类似的问题,可以说是孪生兄弟,且内部实现都差不多,都是通过子类来覆盖父类而已,不过简单工厂是把父类直接摆在客户端,而策略模式是将父类隐藏在Context里面,这样封装更好。
4、举个例子
(1)产品之于加减乘除,水果之于苹果梨橘子香蕉,文具之于笔尺刀,这时产品比较具体、有限和没有多个算法重叠,这时实用简单工厂模式。
(2)产品之于商场促销中的返利(可为300返100、500返200、10000返500等等无数)、折扣(2折、2.5折、6折、9折、9.1折等等无数)、正常购买、消费积分(100元10积分、200元30积分等等无数),这时产品构造又多次重叠,且有在不同时刻应用不同的规则时使用策略模式。
5、总结
简单工厂模式只是解决了对象的创建问题,工厂需要包括所有的产品对象的创建,如果产品对象形式经常变化,就需要经常改动工厂,以致代码重新编译。所以策略模式就诞生了,策略模式---它定义了算法家族,分别封装起来,而不是像简单产品模式一样定义所有的产品类,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户,使客户拥有相同的访问过程。
简单工厂模式的核心是“简单工厂模式就是用来封装所有的产品对象的”。
策略模式理解核心是“策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中遇到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性”。
在基本的策略模式中,选择所用的具体实现的算法的职责由客户端对象承担,并转给策略模式的Context对象。这是策略模式本身纯粹的定义,所以,“选择所用最终怎样处理”还有很多文章可做。
看了课本之后对于这两个模式还是有很多不理解的地方,但是相信随着对设计模式进一步的学习,能够更好地体会到这其中的奥妙,学习是一个循序渐进的过程。
推荐博客
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
CentOS-搭建MinIO集群
一、基础环境 操作系统:CentOS 7.x Minio在线演示 Minio下载 二、准备工作 2.1、机器资源 192.168.1.101 /data1 192.168.1.102 /data2 192.168.1.103 /data3 192.168.1.104 /data4 本集群由4台服务器构成(官方推荐集群最小4台服务器),每个服务器上挂载两个磁盘目录,最小数据挂载点为4个 2.2、创建相关目录(所有节点) 数据存储目录 $mkdir -p /var/minio/bin 启动脚本目录 $ cd /var/minio/bin $ wgethttps://dl.minio.io/server/minio/release/linux-amd64/minio $chmod +x minio 集群配置文件目录 $mkdir -p /etc/minio 三、编写集群启动脚本(所有节点配置文件相同) $vim /var/minio/bin/run.sh #!/bin/bash export MINIO_ACCESS_KEY=minio export MINIO_SECRET_KEY=te...
- 下一篇
产品经理如何有效进行需求管理?
需求是整个软件项目当中最重要一项输入。软件开发和传统生产行业最大的区别在于,需求总是模糊的、主观的和随时变化的。相对于电子产品、汽车等制造行业有形的硬件需求,软件开发的需求的描述和验收是个难以解决的问题。 但是需求又是整个项目能否成功的决定性因素,所以我们必须对需求进行管理,从而使需求成为整个软件工程的基线。使得所有产品、设计、研发、测试、运维工作能围绕着统一的需求开展。保证项目能顺利进行,完成目标。 需求管理的难点? 一般情况下,需求难以管理的原因有以下几方面: 1、需求描述的问题 一般来说,最容易造成开发出来的产品与设计功能不符的原因便是需求描述的问题了。其实大部分情况下,写需求文档的人没有错,看文档的人也没有错。共享文档不等于达成共识。只是因为面对同一段描述,人与人之间的理解不相同,而且这种情况是一定会发生的。所以对于需求,一定要基于团队面对面讨论,保证对需求的理解一致。 2、需求变化的问题 需求变化的原因很多,如一开始没有识别全,新增需求;业务变化导致需求变化;需求有误;需求不清晰等。需求变化将导致从设计方案到编码测试的修改,延迟交付,带来诸多麻烦。这就需要团队在迭代进行前,尽...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果