一、定义、类型及类图

  • 定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。(策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户——出自《大话设计模式》)
  • 类型:行为类模式
  • 类图

策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。在前面说过的行为类模式中,有一种模式也是关注对算法的封装——模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是封装到了封装类Context中,抽象策略Strategy一般是一个接口,目的只是为了定义规范,里面一般不包含逻辑。其实,这只是通用实现,而在实际编程中,因为各个具体策略实现类之间难免存在一些相同的逻辑,为了避免重复的代码,我们常常使用抽象类来担任Strategy的角色,在里面封装公共的代码,因此,在很多应用的场景中,在策略模式中一般会看到模版方法模式的影子。

二、策略模式的结构

  • 环境(Context)角色:持有一个Strategy的引用,也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
  • 抽象策略(Strategy):通常情况下为一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码,此时,策略模式看上去更像是模版方法模式。
  • 具体策略(ConcreteStrategy):具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。

三、策略模式代码实现

interface IStrategy {public void doSomething();
}
class ConcreteStrategy1 implements IStrategy {public void doSomething() {System.out.println("具体策略1");}
}
class ConcreteStrategy2 implements IStrategy {public void doSomething() {System.out.println("具体策略2");}
}
class Context {private IStrategy strategy;public Context(IStrategy strategy){this.strategy = strategy;}public void execute(){strategy.doSomething();}
}public class Client {public static void main(String[] args){Context context;System.out.println("-----执行策略1-----");context = new Context(new ConcreteStrategy1());context.execute();System.out.println("-----执行策略2-----");context = new Context(new ConcreteStrategy2());context.execute();}
}

四、策略模式的优缺点

  • 主要优点:

    1. 策略类之间可以自由切换,由于策略类实现自同一个抽象,所以他们之间可以自由切换。
    2. 易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变原有代码的基础上进行扩展。
    3. 避免使用多重条件,如果不使用策略模式,对于所有的算法,必须使用条件语句进行连接,通过条件判断来决定使用哪一种算法,在上一篇文章中我们已经提到,使用多重条件判断是非常不容易维护的。
  • 主要缺点:
    1. 维护各个策略类会给开发带来额外开销,可能大家在这方面都有经验:一般来说,策略类的数量超过5个,就比较令人头疼了。
    2. 必须对客户端(调用者)暴露所有的策略类,因为使用哪种策略是由客户端来决定的,因此,客户端应该知道有什么策略,并且了解各种策略之间的区别,否则,后果很严重。例如,有一个排序算法的策略模式,提供了快速排序、冒泡排序、选择排序这三种算法,客户端在使用这些算法之前,是不是先要明白这三种算法的适用情况?再比如,客户端要使用一个容器,有链表实现的,也有数组实现的,客户端是不是也要明白链表和数组有什么区别?就这一点来说是有悖于迪米特法则的。
  • 优点补充(出自——大话设计模式):
    1. 策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
    2. 策略模式的Strategy实现层为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
    3. 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
    4. 当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的ConcreteStrategy类中,可以在使用这些行为的类中消除条件语句
    5. 策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不用的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

五、适用常见

做面向对象设计的,对策略模式一定很熟悉,因为它实质上就是面向对象中的继承和多态,在看完策略模式的通用代码后,我想,即使之前从来没有听说过策略模式,在开发过程中也一定使用过它吧?至少在在以下两种情况下,大家可以考虑使用策略模式,

  • 几个类的主要逻辑相同,只在部分逻辑的算法和行为上稍有区别的情况。
  • 有几种相似的行为,或者说算法,客户端需要动态地决定使用哪一种,那么可以使用策略模式,将这些算法封装起来供客户端调用。

策略模式是一种简单常用的模式,我们在进行开发的时候,会经常有意无意地使用它,一般来说,策略模式不会单独使用,跟模版方法模式、工厂模式等混合使用的情况比较多。

六、JDK的策略模式应用

1、ThreadPoolExecutor(线程池)中的RejectedExecutionHandler

学习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,这个参数代表的是拒绝策略(有四种具体的实现:直接抛出异常、使用调用者的线程来处理、直接丢掉这个任务、丢掉最老的任务)

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

2 Java 对象排序中的应用

Comparator 外部比较器接口 我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么可以建立一个该类的比较器来排序,这个比较器只需要实现Comparator接口即可。,通过实现Comparator类来新建一个比较器,然后通过该比较器来对类进行排序。Comparator 接口其实就是一种策略模式的实践 事例代码: 抽象策略类 Comparator

public interface Comparator<T> {int compare(T o1, T o2);boolean equals(Object obj);}

具体策略类 SortComparator

public class SortComparator implements Comparator {@Overridepublic int compare(Object o1, Object o2) {Student student1 = (Student) o1;Student student2 = (Student) o2;return student1.getAge() - student2.getAge();}
}

策略模式上下文 Collections

public class Client {public static void main(String[] args) {Student stu[] = {new Student("张三" ,23),new Student("李四" ,26), new Student("王五" ,22)};Arrays. sort(stu,new SortComparator());System.out.println(Arrays.toString(stu));List<Student> list = new ArrayList<>(3);list.add( new Student("zhangsan" ,31));list.add( new Student("lisi" ,30));list.add( new Student("wangwu" ,35));Collections. sort(list,new SortComparator());System.out.println(list);}}

数据流

countRunAndMakeAscending:355, TimSort (java.util)
sort:220, TimSort (java.util)
sort:1438, Arrays (java.util)
main:20, Client (designpattern.strategy.compare)

调用Collections.sort方法之后走的是Arrays.sort()方法,然后TimSort类中countRunAndMakeAscending方法中调用具体比较器的算法实现进行比较,完成排序。这是大家比较常用的对象排序工具类。

转载于:https://www.cnblogs.com/duanxz/archive/2012/05/28/2520857.html

行为类模式--策略模式相关推荐

  1. 设计模式 — 行为型模式 — 策略模式

    目录 文章目录 目录 策略模式 应用场景 代码示例 策略模式 策略模式中,首先定义了一系列不同的算法,并把它们一一封装起来,然后在策略类中,使这些算法可以相互替换.这意味着,让一个类的行为(算法)可以 ...

  2. 23种模式——策略模式

    目录 策略模式 策略模式的收银软件 策略模式的特点 使用场景 优缺点 策略模式和工厂模式的结合 策略(Strategy)模式 本质:分离算法,选择实现. 策略模式:针对一组算法,将每一个算法封装到具有 ...

  3. 模板模式+策略模式优化

    前言 写在最前面,最近在项目中发现一部分代码,可以用模板模式+策略模式来进行优化. 背景 业务中,系统中对订单状态的处理,需要发送对用户短信发送或者微信推送等操作. 发送短信和微信推送钱,需要处理逻辑 ...

  4. 工厂模式+策略模式组合实现电商促销活动

    项目中大多数设计模式都是组合使用的,对于单个设计模式小伙伴们可以去菜鸟教程学习一下,下面使用 Java 实现的工厂模式+策略模式组合实现电商促销 首先,根据策略的不同,一些需要优惠计算,一些需要普通计 ...

  5. java-抽象工厂模式+工厂方法模式+策略模式简单应用实战(登录场景)

    前言 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性. 设计模式 ...

  6. 工厂模式+策略模式+反射机制解决系统功能模块相似的问题

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 背景 痛点 一.如何根据不同条件获取不同的数据库Mapper? 二.如何根据不同条件创建相应的数据库实体对象? 总结 背景 ...

  7. 进阶学习之旅-设计模式之(委派模式策略模式)

    文章目录 1.课程学习目标 2.内容定位 3.委派模式详解 3.1委派模式的定义 3.2 demo案例 3.2.1模拟Boss指派任务给Leader 由员工完成任务执行 3.2.2 模拟spring ...

  8. springboot 使用工厂模式+策略模式替代多重if 案例

    项目背景: 由于做的是物联网项目,现在需要实现的是网关入网+子设备注册:网关有3个逻辑,分别为首次入网.解绑后同一个人入网(恢复).解绑后换人入网(换人).子设备注册: 原先写法是: if(type ...

  9. 混合模式(工厂方法模式+策略模式+门面模式)

    混合模式(工厂方法模式+策略模式+门面模式) 使用这三种模式设计一个简单的计算器程序:计算器是用于计算数值之间进行数学计算后所获得的值.它包含基本的"加减"功能.以上对以上需求进行 ...

最新文章

  1. 扫描项目里没有使用的图片mac工具,删除没有使用的图片以减小包的体积
  2. 【宝藏女孩】独行40国,风控女孩的环球之旅
  3. golang中的http conn实现分析
  4. HTML字体怎么显示,教你如何用CSS来控制网页字体的显示样式
  5. java文件拷贝时 buff给多大合适_Java复制文件
  6. enum in c language
  7. 数据状态更新时的差异 diff 及 patch 机制
  8. Nginx完美解决前后端分离端口号不同导致的跨域问题
  9. 数据库oracle有哪些函数,Oracle函数大全
  10. ct与x光的哪个辐射大_听说做一次CT所受到的辐射剂量和损害 = 拍400张X光片?
  11. SpringBoot整合MyBatis后台分页前端BootstrapTable添加删除查看编辑搜索数据(一)
  12. 专利服务器拒收 文件解压异常,电子申请常见问题解答20161024.doc-中国专利电子申请网.doc...
  13. QQ自动播放动态视频json卡片怎么换地址
  14. 读取图像教程,生成h5py文件的教程
  15. 虎赢大数据:“企业工商数据价值挖掘”,是2020年大数据创业发展的方向之一
  16. java鼠标乱跑_光标乱跑怎么办 光标乱跑解决方法【图文】
  17. 解决SpringBoot项目jar包启动慢
  18. JavaWeb查漏补缺
  19. [希腊神话--英语]另类重看英语词汇---序言
  20. 7-32 哥尼斯堡的“七桥问题” c语言

热门文章

  1. 一款非常好用的Linux下的C/C++ IDE
  2. Useful websites for library
  3. what should you do at the new arrival of the place
  4. CERTIFICATE OF APPRECIATION FOR DONATION FOR IBSS
  5. 我的未来规划最新版本
  6. 远程断开远程桌面会话之方法
  7. QT. 学习之路 一
  8. prepare 和 row_count()一起使用的误区
  9. 产品设计体会(9000)人人都是产品经理,系列说明
  10. xtrabackup增量备份mysql +MHA