GOF 《设计模式:可复用面向对象软件设计的基础》中的模式,应当算是模式归纳的鼻祖(并非他们最早发现/使用了模式,而是将已有的模式进行了整合归纳),而我们现在对于模式的学习基本上都是基于Gof的设计模式。今天主要说说行为型模式中的一个:策略模式。

模式定义

意图:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

动机:

客户程序如果直接包含策略算法代码,将会变得很复杂。(策略算法本身足够复杂)

不同的时候需要不同的算法   (if....else....)

模式类图

阐述与讨论

策略模式是我们在开发中常用的模式之一。网上关于策略模式也有很多介绍,这里再次提出,是期望给出“正规”的模式,在我初学设计模式时,也经常会被搞得不知所云,众说纷纭还给出代码,但几乎都不太一样,我也曾被策略模式搞得迷糊(主要是context),因此再次找出GOF原本进行分析- -

最常见的疑惑问题:策略模式和简单工厂模式进行比较。两者区别还是比较大的,不管是从语义还是实现上。

下面给出简单工厂的类图(GOF模式中没有简单工厂---只有抽象工厂和工厂方法):

对比简单工厂和策略模式类图很容易发现区别: 工厂(Factory)是依赖Product接口,同时依赖于具体产品(ProductA和ProductB),而策略模式中,Context是包含了Stategy接口,同时并不依赖具体的策略类。

通过代码很容易就可以看出区别:

策略模式代码:

1

1 packagestrategydemo;2 /**

3 *@author: xiaolu 2018年2月6日4 * @todo : 策略上下文5 */

6 public classContext {7 //包含关系

8 privateStrategy strategy ;9 //这个类中包含具体策略需要的其他参数,必要时可以将自己传递给策略类(GOF)

10 publicContext(Strategy strategy){11 this.strategy =strategy;12 }13

14 public intget(){15 return this.strategy.algorithm();16 }17 }

1 packagestrategydemo;2

3 /**

4 *@author: xiaolu 2018年2月6日5 * @todo : 策略接口6 */

7 public class StrategyB implementsStrategy {8 @Override9 public intalgorithm() {10 //这里的逻辑应当比较复杂,否则没有必要使用策略类11 //仅作说明

12 return 0;13 }14

15 }

1 packagestrategydemo;2

3 public class StrategyA implementsStrategy {4 @Override5 public intalgorithm() {6 //这里的逻辑应当比较复杂,否则没有必要使用策略类7 //仅作说明

8 return 1;9 }10

11 }

1 packagestrategydemo;2

3 /**

4 *@author: xiaolu 2018年2月6日5 * @todo : 策略接口6 */

7 public class StrategyB implementsStrategy {8 @Override9 public intalgorithm() {10 //这里的逻辑应当比较复杂,否则没有必要使用策略类11 //仅作说明

12 return 0;13 }14

15 }

1 packagestrategydemo;2 /**

3 *@author: xiaolu 2018年2月6日4 * @todo : 客户端5 */

6 public classMain {7 public static voidmain(String[] args) {8 //具体策略类

9 Strategy a = newStrategyA();10 //Context

11 Context ctx = newContext(a);12

13 System.out.println(ctx.get());14 }15 }

代码结构和名称大体按照策略类图所给出的。可以看到客户端是“知道”(或者说依赖于)具体策略类的。而Context对于具体策略类并不存在任何依赖(无知),只是“包含”(类中属性)了策略接口。

下面给出简单工厂实现:

1 packagesimplefactory;2

3 /**

4 *@author: xiaolu 2018年2月6日5 * @todo :产品接口6 */

7 public interfaceProduct {8 //...... 工厂模式中,工厂主要用于产生产品,并不涉及产品的操作,因此此处省略具体产品的操作

9 }

1 packagesimplefactory;2

3 /**

4 *@author: xiaolu 2018年2月6日5 * @todo : 产品A6 */

7 public class ProductA implementsProduct {8

9 }

packagesimplefactory;/***@author: xiaolu 2018年2月6日

* @todo : 产品B*/

public class ProductB implementsProduct {

}

1 packagesimplefactory;2

3 /**

4 *@author: xiaolu 2018年2月6日5 * @todo : 简单工厂6 */

7 public classFactory {8 //返回值为产品接口

9 public Product get(inti) {10 if (i == 0) {11 //返回具体的产品(有依赖)

12 return newProductA();13 } else if (i == 1) {14 //返回具体的产品(有依赖)

15 return newProductB();16 } else{17 throw new RuntimeException("不支持");18 }19 }20 }

1 packagesimplefactory;2

3 /**

4 *@author: xiaolu 2018年2月6日5 * @todo : 客户端6 */

7 public classMain {8 public static voidmain(String[] args) {9 Factory f = newFactory();10 //客户端不知道(不依赖)具体产品

11 Product p = f.get(1);12 //执行p的操作

13 }14 }

对比类图和代码实现,应该从结构上很容易区分两者。更重要的是:策略模式是行为型模式,而工厂模式是创建型模式!通俗的说,工厂模式只负责产生“按你所需”的产品,至于你如何使用,工厂是无知的(这也是我为什么没有在产品接口中定义方法,因为不固定)。而策略模式中,具体的策略类是客户端“知道”的(这也是是否需要直接使用策略模式的一个选择【也可以规避它-策略+工厂】),而Context则负责“转发”(只是转发吗?)这里不妨想想,为什么需要Context,如果没有Context会如何呢?如果没有:

1 Strategy strategy = newStrategyA();2 strategy.algorithm();

好像还反而简单了?Context是Strategy和Main(客户端)之间的一个间接层,可以用来封装需要传递给Strategy的数据结构和参数。

相对于普通的多态结构,策略模式强调的是【算法】的可相互替代性。再次强调:如果具体策略类并不复杂就不要用策略模式(自找烦恼)。而策略类的一个弊端:客户端类需要“知道”具体策略类------可以通过加一个工厂解决。简单工厂的意义是什么呢? 符合SRP,单一职能,降低耦合 ,还有一个作用---------转换。大部分的if....else代码我们并不能规避,只是从“这里”移到了“那里”,好处是代码更明确,更清晰,更容易扩展,而简单工厂做这种转换非常的合适。使用简单工厂+策略模式的类图如下:

(上面的线条有点多?是的,我画出了所有的依赖关系)。在这里,可以看到Client端不再依赖于具体的策略类(策略A/B),.而是依赖于工厂,而工厂在这里可以做出转换。假设测试都是关于打折的,现在要求是3-9月份,使用打折策略A(打8折),其余时间采用B策略(打9折)......那么就存在一种映射关系:

3-9月份--------------策略A

1-2和10-12月份---策略B

在工厂中就是进行进行这种转换的最好地方(什么?工厂中存在了if.....else.....嗯是这样的【使用Map来替代,换汤没换药】),同时工厂仅做了一件事,而没有将映射策略放在客户端(客户端往往还有很多其它的处理,并非说放在客户端不能实现,只是本身客户端就很复杂了,不想再给它增加复杂性),到这里基本上可以结束,但是有人说了,不符合OCP(开闭原则),有新的映射到来呢,还需要修改工厂,于是简单工厂会升级为工厂方法.......拒绝模式的诱惑和过度优化,我个人理解:代码写的自己觉得舒服,容易阅读就好,过犹不及!不要一看到if.....else就深恶痛绝---然后去考虑某个(例如策略)模式去替代,这样做之前,请多多三思。在写代码过程中必须意识到复杂性和灵活性大多时候成正比(相对有模式的引入,没有模式引入的代码更为简单-----如果是很习惯模式可能除外,但是请考虑新手)。

最后再提一个经常误导我的:有人将Factory和Context进行了“糅合”(就是Context直接依赖了具体策略,看图吧)

这不是和简单工厂的类图“一模一样”吗?是的,因为这个原因,所以才会将工厂和策略模式搬出来做对比!这种用法不做好坏评论,从GOF来说偏离了模式本意(所以看到策略这种实现,不要觉得疑惑【这是人为的做了修改-----不过改的好与不好......呵呵】),更像是工厂的形,“策略”的神。个人感觉:在简单的时候(Context用来为Strategy准备参数,如果只是很简单的情况---转发/委托,我觉得这种方式也无不可------相对于上面的工厂+策略,确实简单了很多),但是如果Context本身就很复杂,我个人还是建议还原为工厂+策略。只是我们在看到这种很“亲密”的且称为策略的模式时,不要被迷惑和搞混就好。

打折策略模式java_策略模式(java)相关推荐

  1. command模式 java_命令模式(Command)_java实现

    //20210129 写在前面:刚期末考试完,考了面向对象,里边儿有23个设计模式,我寻思着考完挨个儿实现一下,本文实现命令模式 命令模式核心思想: 将操作封装成一个对象,请求者发送请求给包装有命令的 ...

  2. java策略模式 工厂模式_策略模式和工厂模式搭配使用

    策略模式和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套 需求 针对店下商铺,有这样一个需求,对用户客户分为了普通客户.vip客户.超级vip用户.专属vip用户4个等级,每当用户购买商 ...

  3. Java设计模式之策略模式与状态模式

    一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...

  4. Java设计模式(备忘录模式-解释器模式-状态模式-策略模式-职责链模式)

    Java设计模式Ⅶ 1.备忘录模式 1.1 备忘录模式概述 1.2 代码理解 2.解释器模式 2.1 解释器模式概述 3.状态模式 3.1 状态模式概述 3.2 代码理解 4.策略模式 4.1 策略模 ...

  5. Java设计模式之十一 ---- 策略模式和模板方法模式

    前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...

  6. java状态模式和策略模式_Java状态和策略设计模式之间的差异

    java状态模式和策略模式 为了在Core Java应用程序中正确使用状态和策略设计模式,对于Java开发人员清楚地了解它们之间的区别很重要. 尽管状态和策略设计模式的结构相似,并且都基于开放式封闭设 ...

  7. java输出不同颜色_Java设计模式-策略模式、状态模式

    推荐阅读: 一只Tom猫:都是"Redis惹的祸",害我差点挂在美团三面,真是"虚惊一场"! java喵:6大面试技能树:JAVA基础+JVM+算法+数据库+计 ...

  8. Java用最少代码实现五子棋-玩家对战模式-人机对战模式-电脑策略对战

    Java用最少代码实现五子棋-玩家对战模式-人机对战模式-电脑策略对战 玩家对战模式 背景说明 代码实现 人机对战模式 背景说明 完整代码实现 电脑根据优势分数对战 背景说明 完整代码实现 小结 玩家 ...

  9. 图解Java设计模式学习笔记——行为型模式(模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式)

    一.模板方法模式(模板模式)--钩子方法 1.需求-豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程选材-->添加配料-->浸泡-->放到豆浆机打碎. 通过添加不同的配料 ...

最新文章

  1. TCP服务器和客户端的链接例子(侧重点在注意关闭套接子,减少套接子的描述子)
  2. JQuery中each()的使用方法说明
  3. 简单配置jena在eclipse的开发环境
  4. 图解命令行手动编译构建一个win32汇编程序
  5. MATLAB从入门到精通系列-非线性曲线拟合函数lsqcurve()详解
  6. Headmaster's Headache
  7. mysql录数据总是错误_MySQL数据库出错
  8. 简单一招搞定公司牛人 转自 潘文富
  9. 如何使用BetterZip mac版将大文件分卷压缩
  10. php 规则路由器,ThinkPHP6路由踩坑之变量规则
  11. string与wstring转换
  12. 手把手·教你用 Echarts 画 ChinaMap
  13. 0基础学RS(十三)思科交换机上的Access模式和trunk模式以及配置
  14. 计算机技术员自我介绍,技术员的自我介绍范文
  15. 关于战棋对战化的设想和实现
  16. RF Python扩展测试库
  17. C# 编写VLC视频事件处理程序 libvlc libvlc_event_attach libvlc_event_manager libvlc_event_type ibvlc_event_e用法
  18. 22湖南大学计算机学硕上岸经验
  19. arm64服务器性能,80核ARM服务器有多恐怖 性能比64核霄龙还强
  20. 【测试用例】测试用例设计的关键点总结

热门文章

  1. 【JAVA实战】用socket通信编程制作多人聊天室
  2. html图片逆时针转换,HTML+CSS入门 如何解决iOS下html上传图片被旋转问题
  3. TLE两行根数简介及获取方法
  4. 2014 junior T1 珠心算测试 题解
  5. git clone 太慢咋搞?两行命令解决(需要纸飞机)
  6. 关于cache和cache miss
  7. Nodejs读取文件、查找文件位置
  8. 每日一解 电话号码的字母组合
  9. 计算机一级考试是不是有手就行,高考有手就行?职业选手jkl说完之后才意识到,自己根本没有参加过...
  10. 计算机类本科专业国家质量标准,计算机专业国家职业标准.doc