前言

只有光头才能变强

回顾前面:

  • 给女朋友讲解什么是代理模式
  • 包装模式就是这么简单啦
  • 单例模式你会几种写法?
  • 工厂模式理解了没有?

无论是面试还是个人的提升,设计模式是必学的。今天来讲解策略模式~

一、策略模式介绍

我一次听到策略模式这个词,是在我初学JDBC的时候。不知道大家有没有用过DBUtils这个组件。当时初学跟着视频学习,方立勋老师首先是让我们先自己封装一下JDBC的一些常用的操作(实际上就是模仿DBUtils这个组件)。

当时候的问题是这样的:我们打算封装一下query()查询方法,传入的参数有String sql , Object[] objects(指定SQL语句和对应的参数)。我们想根据不同的业务返回不同的值。

  • 比如说,有的时候我们返回的是一条数据,那我们想将这条数据封装成一个Bean对象
  • 比如说,有的时候我们返回的是多条数据,那我们想将这多条数据封装成一个List<Bean> 集合
  • 比如说,有的时候我们返回的是xxxx数据,那我们想将这多条数据封装成一个Map<Bean> 集合
  • ........等等等

当时解决方案是这样的:

  • 先定义一个接口:ResultSetHandler(调用者想要对结果集进行什么操作,只要实现这个接口即可)

    • 这个接口定义了行为。Object hanlder(ResultSet resultSet);
  • 然后实现上面的接口,比如我们要封装成一个Bean对象,就是public class BeanHandler implements ResultSetHandler
  • 调用的时候,实际上就是query()查询方法多一个参数 query(String sql, Object[] objects, ResultSetHandler rsh)。调用者想要返回什么类型,只要传入相对应的ResultSetHandler实现类就是了。

代码如下:

query方法://这个方法的返回值是任意类型的,所以定义为Object。public static Object query(String sql, Object[] objects, ResultSetHandler rsh) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {connection = getConnection();preparedStatement = connection.prepareStatement(sql);//根据传递进来的参数,设置SQL占位符的值if (objects != null) {for (int i = 0; i < objects.length; i++) {preparedStatement.setObject(i + 1, objects[i]);}}resultSet = preparedStatement.executeQuery();//调用调用者传递进来实现类的方法,对结果集进行操作return rsh.hanlder(resultSet);}接口:/** 定义对结果集操作的接口,调用者想要对结果集进行什么操作,只要实现这个接口即可* */public interface ResultSetHandler {Object hanlder(ResultSet resultSet);}接口实现类(Example)://接口实现类,对结果集封装成一个Bean对象public class BeanHandler implements ResultSetHandler {//要封装成一个Bean对象,首先要知道Bean是什么,这个也是调用者传递进来的。private Class clazz;public BeanHandler(Class clazz) {this.clazz = clazz;}@Overridepublic Object hanlder(ResultSet resultSet) {try {//创建传进对象的实例化Object bean = clazz.newInstance();if (resultSet.next()) {//拿到结果集元数据ResultSetMetaData resultSetMetaData = resultSet.getMetaData();for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {//获取到每列的列名String columnName = resultSetMetaData.getColumnName(i+1);//获取到每列的数据String columnData = resultSet.getString(i+1);//设置Bean属性Field field = clazz.getDeclaredField(columnName);field.setAccessible(true);field.set(bean,columnData);}//返回Bean对象return bean;}

这就是策略模式??就这??这不是多态的使用吗??

1.1策略模式讲解

《设计模式之禅》:

定义一组算法,将每个算法都封装起来,并且使他们之间可以互换

策略模式的类图是这样的:

策略的接口和具体的实现应该很好理解:

  • 策略的接口相当于我们上面所讲的ResultSetHandler接口(定义了策略的行为)
  • 具体的实现相当于我们上面所讲的BeanHandler实现(接口的具体实现)

    • 具体的实现一般还会有几个,比如可能还有ListBeanHandler、MapBeanHandler等等

令人想不明白的可能是:策略模式还有一个Context上下文对象。这对象是用来干什么的呢?

《设计模式之禅》:

Context叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。

在知乎上也有类似的问题(为什么不直接调用,而要通过Person?):

说白了,通过Person来调用更符合面向对象(屏蔽了直接对具体实现的访问)。

首先要明白一个道理,就是——到底是 “人” 旅游,还是火车、汽车、自行车、飞机这些交通工具旅游?

如果没有上下文的话,客户端就必须直接和具体的策略实现进行交互了,尤其是需要提供一些公共功能或者是存储一些状态的时候,会大大增加客户端使用的难度;引入上下文之后,这部分工作可以由上下文来完成,客户端只需要和上下文进行交互就可以了。这样可以让策略模式更具有整体性,客户端也更加的简单

具体的链接:

  • https://www.zhihu.com/question/31162942

所以我们再说回上文的通用类图,我们就可以这样看了:

1.2策略模式例子

现在3y拥有一个公众号,名称叫做Java3y。3y想要这让更多的人认识到Java3y这个公众号。所以每天都在想怎么涨粉(hahah

于是3y就开始想办法了(操碎了心),同时3y在这一段时间下来发现涨粉的方式有很多。为了方便,定义一个通用的接口方便来管理和使用呗。

接口:


/*** 增加粉丝策略的接口(Strategy)*/
interface IncreaseFansStrategy {void action();
}

涨粉的具体措施,比如说,请水军:


/*** 请水军(ConcreteStrategy)*/
public class WaterArmy implements IncreaseFansStrategy {@Overridepublic void action() {System.out.println("3y牛逼,我要给你点赞、转发、加鸡腿!");}
}

涨粉的具体措施,比如说,认真写原创:


/*** 认真写原创(ConcreteStrategy)*/
public class OriginalArticle implements IncreaseFansStrategy{@Overridepublic void action() {System.out.println("3y认真写原创,最新一篇文章:《策略模式,就这?》");}
}

3y还想到了很多涨粉的方法,比如说送书活动啊、商业互吹啊等等等...(这里就不细说了)

说到底,无论是哪种涨粉方法,都是通过3y去执行的。


/*** 3y(Context)*/
public class Java3y {private IncreaseFansStrategy strategy ;public Java3y(IncreaseFansStrategy strategy) {this.strategy = strategy;}// 3y要发文章了(买水军了、送书了、写知乎引流了...)。// 具体执行哪个,看3y选哪个public void exec() {strategy.action();}
}

所以啊,每当到了发推文的时候,3y就可以挑用哪种方式涨粉了:

public class Main {public static void main(String[] args) {// 今天2018年12月24日Java3y java3y = new Java3y(new WaterArmy());java3y.exec();// 明天2018年12月25日Java3y java4y = new Java3y(new OriginalArticle());java4y.exec();// ......}
}

执行结果:

1.3策略模式优缺点

优点:

  • 算法可以自由切换

    • 改一下策略很方便
  • 扩展性良好

    • 增加一个策略,就多增加一个类就好了。

缺点:

  • 策略类的数量增多

    • 每一个策略都是一个类,复用的可能性很小、类数量增多
  • 所有的策略类都需要对外暴露

    • 上层模块必须知道有哪些策略,然后才能决定使用哪一个策略

1.4JDK的策略模式应用

不知道大家还能不能想起ThreadPoolExecutor(线程池):线程池你真不来了解一下吗?

学习ThreadPoolExecutor(线程池)就肯定要知道它的构造方法每个参数的意义:

/*** Handler called when saturated or shutdown in execute.*/private volatile RejectedExecutionHandler handler;public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {//....this.handler = handler;}/*** Invokes the rejected execution handler for the given command.* Package-protected for use by ScheduledThreadPoolExecutor.*/final void reject(Runnable command) {handler.rejectedExecution(command, this);}

其中我们可以找到RejectedExecutionHandler,这个参数代表的是拒绝策略(有四种具体的实现:直接抛出异常、使用调用者的线程来处理、直接丢掉这个任务、丢掉最老的任务)

其实这就是策略模式的体现了。

最后

看完会不会觉得策略模式特别简单呀?就一个算法接口、多个算法实现、一个Context来包装一下,就完事了。

推荐阅读和参考资料:

  • https://www.cnblogs.com/lewis0077/p/5133812.html
  • 《设计模式之禅》

乐于分享和输出干货的Java技术公众号:Java3y。

文章的目录导航

  • https://github.com/ZhongFuCheng3y/3y

策略模式原来这么简单!相关推荐

  1. 原来使用 Spring 实现策略模式可以这么简单!

    策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法,可以替代代码中大量的 if-else. 比如我们生活中的场景:买东西结账可以使用微信支付.支付宝支付或者银行 ...

  2. 设计模式之简单工厂模式与策略模式

    目录 一.简单工厂模式 二.策略模式 三.简单工厂和策略模式的相同和不同点 四.SpringBoot中用简单工厂搭配策略模式 一.简单工厂模式 概述:定义一个工厂类,它可以根据参数的不同返回不同的实例 ...

  3. 【设计模式】java设计模式之 -- 策略模式

    对于代码中总是会有需要变化的部分和需要固定不变的部分.对于需要变化的部分,一般可以采用继承的方式,让子类对父类的方法进行重写,以改变已有的行为:如果变化的部分并不是所有子类都必须要有的,那就可以采用接 ...

  4. 设计模式学习---策略模式

    最近在看"Head First 设计模式"这本书,便想将自己所学的记录下来以加深理解,文中肯定有许多不足之处,请各位前辈们指出. 什么是设计模式 设计模式并不是某种开发语言中的工具 ...

  5. 策略模式(Strategy)简介

    一, 回顾简单工厂模式(SimpleFactory) 上一篇博文: http://blog.csdn.net/nvd11/article/details/41855937 还是用回那个计算器作例子. ...

  6. java spring 实现策略,Spring 环境下实现策略模式的示例

    背景 最近在忙一个需求,大致就是给满足特定条件的用户发营销邮件,但是用户的来源有很多方式:从 ES 查询的.从 csv 导入的.从 MongoDB 查询-.. 需求很简单,但是怎么写的优雅,方便后续扩 ...

  7. 【PHP设计模式 08_CeLue.php】策略模式

    <?php /*** [策略模式]----和"简单工厂"模式很相似* 根据不同运算符计算两个数的运算结果* 常规方式就是判断运算符然后进行if...else的操作* 现在使用 ...

  8. 设计模式-优惠券-策略模式

    策略模式定义与实现 策略模式的定义 ​ 首先我们可以先看一下策略模式的定义: Define a family of algorithms,encapsulate each one,and make t ...

  9. 锦囊妙计——策略模式

    策略模式 ​ Strategy Pattern:策略模式是GoF23中设计模式中属于行为型设计模式的一种. ​ 策略模式的关键点就在于策略两字,策略是一种方法,一种方式,一种计策.用术语来讲的话,可以 ...

最新文章

  1. 2D-2D:对极约束
  2. Android软键盘的显示与隐藏
  3. java1.8 新特性
  4. c查看变量类型_C语言的变量、常量及运算
  5. jQuery在线选座订座(影院篇)
  6. iOS: 教你给UI控件添加Badge(消息提醒小圆点)
  7. java获取动态天气api,java调用中国天气网api获得天气预报信息
  8. IOUtils pom 依赖
  9. 软件测试结果分析和质量报告
  10. python收取126或163邮件
  11. C# 使用Zebra斑马打印机打印ZPL文件工具
  12. 路由器使用Caddy搭建Webdav服务
  13. 茴字的四种写法—移动适配方案的进化
  14. 证书相关的玩意儿(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12)
  15. Spring定时器之翘楚-Quartz
  16. 博途组态阀岛_SMC EX260总线阀岛
  17. 开源工具利器之基于主机的IDS:Wazuh
  18. 树莓派如何跟踪附近的飞机,安装和配置Flightradar24
  19. SpringBoot 配置Druid监控页面
  20. 常见胸肌问题解答(五):下缘不够清晰

热门文章

  1. virtualbox 安装ubuntu 时,看不到继续、退出按钮?共享文件无权限?
  2. python中矩阵拼接_numpy实现合并多维矩阵、list的扩展方法
  3. 幼儿园python_[Python]猜数字游戏AI版的实现(幼儿园智商AI)
  4. Castle DynamicProxy基本用法(AOP)
  5. 兼容IE8,滚动加载下一页
  6. Codeforces 479【E】div3
  7. java时间计算,获取某月第一天和最后一天
  8. Linux命令缩写来由
  9. 关于C# WinForm中进度条的实现方法
  10. 11gR2游标共享新特性带来的一些问题以及_cursor_features_enabled、_cursor_obsolete_threshold和106001 event...