前言:本文主要介绍设计模式中的策略模式,准备按照以下几个方面展开:
什么是策略模式
策略模式结构和UML图
策略模式在JDK中的应用
一、什么是策略模式以及策略模式功能
1.1 为什么需要策略模式?
1)完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
2)在软件系统中,很多算法可以实现某一功能,比如查找、排序。这里以查找算法为例说明,如果我们需要提供多种查找算法,可以将这些算法写在一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…等条件判断语句来进行选择。但是这两种实现方式有个弊端,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。维护起来比较困难。
3)除了提供专门的查找算法类之外,还可以在客户端程序中直接包含算法代码,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。(这里的在客户端中包含算法代码的意思就好比我们在包含main函数的类里去实现算法,而不专门提供封装算法的类)
4)为了解决这些问题,可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。
1.2 什么是策略模式?
策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
二、策略模式结构和UML图
2.1 策略模式结构
策略模式包含如下角色:
Context: 环境类
Strategy: 抽象策略类
ConcreteStrategy: 具体策略类
其中Context类持有Strategy的引用,ConcreteStrategy实现Strategy接口。
2.2 策略模式UML图
image.png
2.3 策略模式Demo
以上面说的排序算法的选择为例,写一个Demo。
首先定义抽象策略类AbstractSort
public interface AbstractSort { void sort(); }
然后定义具体策略类ConcreteSort1
,ConcreteSort2
,ConcreteSort3
public class ConcreteSort1 implements AbstractSort { @Override public void sort() { System.out.println("使用快速排序"); } }
public class ConcreteSort2 implements AbstractSort { @Override public void sort() { System.out.println("使用归并排序"); } }
public class ConcreteSort3 implements AbstractSort { @Override public void sort() { System.out.println("使用堆排序"); } }
接着定义Context
环境类
public class Context { public AbstractSort method; public Context(AbstractSort abstractSort) { this.method = abstractSort; } public void contextSort() { method.sort(); } }
最后定义客户端类Main
public class Main { public static void main(String[] args) { //传入不同的具体策略即可 Context context = new Context(new ConcreteSort2()); context.contextSort(); } }
三、策略模式在JDK中的应用
3.1 比较器Comparator
在Java的集合框架中,经常需要通过构造方法传入一个比较器Comparator,或者创建比较器传入Collections的静态方法中作为方法参数,进行比较排序等,使用的是策略模式。
在该比较架构中,Comparator就是一个抽象的策略;一个类实现该结构,并实现里面的compare方法,该类成为具体策略类;Collections类就是环境角色,他将集合的比较封装成静态方法对外提供api。
3.2 ThreadPoolExecutor中的四种拒绝策略
在创建线程池时,需要传入拒绝策略,当创建新线程使当前运行的线程数超过maximumPoolSize时,将会使用传入的拒绝策略进行处理。
AbortPolicy:直接抛出异常。
CallerRunsPolicy:只用调用者所在线程来运行任务。
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
DiscardPolicy:不处理,丢弃掉。
作者:小北觅
链接:https://www.jianshu.com/p/8e59767067a8