智能摘要文章源自JAVA秀-https://www.javaxiu.com/30601.html
在设计模式中,可以使用工厂模式或者策略模式来处理这类问题,之前已经分享了工厂模式,感兴趣的同学可以去复习一下。定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。在源码中有RejectedExecutionHandler这个抽象异常策略接口,同时它也有四种拒绝策略。这就是在框架中的体现了,根据自己的业务场景,合理的选择线程池的异常策略。以上就讲完了策略模式,整体看上去其实还是比较简单的,还是那句话学习设计模式我们还是要学习每种设计模式的思想,任何一种设计模式存在即合理。文章源自JAVA秀-https://www.javaxiu.com/30601.html
原文约 2365 字 | 图片 7 张 | 建议阅读 5 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/30601.html
策略模式
三太子敖丙 三太子敖丙 文章源自JAVA秀-https://www.javaxiu.com/30601.html
收录于话题文章源自JAVA秀-https://www.javaxiu.com/30601.html
#设计模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
8个文章源自JAVA秀-https://www.javaxiu.com/30601.html
最近有一个学妹在跟我沟通如何有效的去避免代码中一长串的if else判断或者switch条件判断?针对更多的回答就是合理的去使用设计来规避这个问题。文章源自JAVA秀-https://www.javaxiu.com/30601.html
在设计模式中,可以使用工厂模式或者策略模式来处理这类问题,之前已经分享了工厂模式,感兴趣的同学可以去复习一下。文章源自JAVA秀-https://www.javaxiu.com/30601.html
设计模式系列往期文章:文章源自JAVA秀-https://www.javaxiu.com/30601.html
单例模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
工厂模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
流程引擎文章源自JAVA秀-https://www.javaxiu.com/30601.html
建造者模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
原型模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
责任链模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
观察者模式文章源自JAVA秀-https://www.javaxiu.com/30601.html
那么工厂模式和策略模式有什么区别呢?文章源自JAVA秀-https://www.javaxiu.com/30601.html
工厂模式是属于创建型设计模式,主要用来针对不同类型创建不同的对象,达到解偶类对象。文章源自JAVA秀-https://www.javaxiu.com/30601.html
策略模式是属于行为型设计模式,主要是针对不同的策略做出对应行为,达到行为解偶文章源自JAVA秀-https://www.javaxiu.com/30601.html
本次就来具体聊聊策略模式它是如何做到行为解耦文章源自JAVA秀-https://www.javaxiu.com/30601.html
大纲
文章源自JAVA秀-https://www.javaxiu.com/30601.html
定义
什么是策略模式?它的原理实现是怎么样的?文章源自JAVA秀-https://www.javaxiu.com/30601.html
定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。以上定义来自设计模式之美文章源自JAVA秀-https://www.javaxiu.com/30601.html
感觉有点抽象?那就来看一张结构图吧文章源自JAVA秀-https://www.javaxiu.com/30601.html
文章源自JAVA秀-https://www.javaxiu.com/30601.html
Strategy(抽象策略):抽象策略类,并且定义策略执行入口文章源自JAVA秀-https://www.javaxiu.com/30601.html
ConcreteStrategy(具体策略):实现抽象策略,实现algorithm方法文章源自JAVA秀-https://www.javaxiu.com/30601.html
Context(环境):运行特定的策略类。文章源自JAVA秀-https://www.javaxiu.com/30601.html
这么看结构其实还是不复杂的,而且跟状态模式类似。文章源自JAVA秀-https://www.javaxiu.com/30601.html
那么这个代码怎么实现?文章源自JAVA秀-https://www.javaxiu.com/30601.html
举个例子,汽车大家肯定都不陌生,愿大家早日完成汽车梦,汽车的不同档(concreteStrategy)就好比不同的策略,驾驶者选择几档则汽车按几档的速度前进,整个选择权在驾驶者(context)手中。文章源自JAVA秀-https://www.javaxiu.com/30601.html
public interface GearStrategy { // 定义策略执行方法 void algorithm(String param);}
首先还是先定义抽象策略文章源自JAVA秀-https://www.javaxiu.com/30601.html
这里是用接口的形式,还有一种方式可以用抽象方法abstract来写也是一样的。具体就看大家自己选择了。文章源自JAVA秀-https://www.javaxiu.com/30601.html
public abstract class GearStrategyAbstract { // 定义策略执行方法 abstract void algorithm(String param);}
public class GearStrategyOne implements GearStrategy { @Override public void algorithm(String param) { System.out.println("当前档位" + param); }}
其次定义具体档位策略,实现algorithm方法。文章源自JAVA秀-https://www.javaxiu.com/30601.html
public class Context { // 缓存所有的策略,当前是无状态的,可以共享策略类对象 private static final Map<String, GearStrategy> strategies = new HashMap<>(); // 第一种写法 static { strategies.put("one", new GearStrategyOne()); } public static GearStrategy getStrategy(String type) { if (type == null || type.isEmpty()) { throw new IllegalArgumentException("type should not be empty."); } return strategies.get(type); } // 第二种写法 public static GearStrategy getStrategySecond(String type) { if (type == null || type.isEmpty()) { throw new IllegalArgumentException("type should not be empty."); } if (type.equals("one")) { return new GearStrategyOne(); } return null; } public static void main(String[] args) { // 测试结果 GearStrategy strategyOne = Context.getStrategy("one"); strategyOne.algorithm("1档"); // 结果:当前档位1档 GearStrategy strategyTwo = Context.getStrategySecond("one"); strategyTwo.algorithm("1档"); // 结果:当前档位1档 }}
最后就是实现运行时环境(Context),你可以定义成StrategyFactory,但都是一个意思。文章源自JAVA秀-https://www.javaxiu.com/30601.html
在main方法里面的测试demo,可以看到通过不同的type类型,可以实现不同的策略,这就是策略模式主要思想。文章源自JAVA秀-https://www.javaxiu.com/30601.html
在Context里面定义了两种写法:文章源自JAVA秀-https://www.javaxiu.com/30601.html
第一种是维护了一个strategies的Map容器。用这种方式就需要判断每种策略是否可以共享使用,它只是作为算法的实现。文章源自JAVA秀-https://www.javaxiu.com/30601.html
第二种是直接通过有状态的类,每次根据类型new一个新的策略类对象。这个就需要根据实际业务场景去做的判断。文章源自JAVA秀-https://www.javaxiu.com/30601.html
框架的应用
策略模式在框架中也在一个很常见的地方体现出来了,而且大家肯定都有使用过。文章源自JAVA秀-https://www.javaxiu.com/30601.html
那就是JDK中的线程池ThreadPoolExecutor文章源自JAVA秀-https://www.javaxiu.com/30601.html
文章源自JAVA秀-https://www.javaxiu.com/30601.html
首先都是类似于这样定义一个线程池,里面实现线程池的异常策略。文章源自JAVA秀-https://www.javaxiu.com/30601.html
这个线程池的异常策略就是用的策略模式的思想。文章源自JAVA秀-https://www.javaxiu.com/30601.html
文章源自JAVA秀-https://www.javaxiu.com/30601.html
在源码中有RejectedExecutionHandler这个抽象异常策略接口,同时它也有四种拒绝策略。关系图如下:文章源自JAVA秀-https://www.javaxiu.com/30601.html
文章源自JAVA秀-https://www.javaxiu.com/30601.html
文章源自JAVA秀-https://www.javaxiu.com/30601.html
这就是在框架中的体现了,根据自己的业务场景,合理的选择线程池的异常策略。文章源自JAVA秀-https://www.javaxiu.com/30601.html
业务改造举例
在真实的业务场景中策略模式也还是应用很多的。文章源自JAVA秀-https://www.javaxiu.com/30601.html
在社交电商中分享商品是一个很重要的环节,假设现在要我们实现一个分享图片功能,比如当前有 单商品、多商品、下单、会场、邀请、小程序链接等等多种分享场景。文章源自JAVA秀-https://www.javaxiu.com/30601.html
文章源自JAVA秀-https://www.javaxiu.com/30601.html
针对上线这个流程图先用if else语句做一个普通业务代码判断,就像下面的这中方式:文章源自JAVA秀-https://www.javaxiu.com/30601.html
public class SingleItemShare { // 单商品 public void algorithm(String param) { System.out.println("当前分享图片是" + param); }}public class MultiItemShare { // 多商品 public void algorithm(String param) { System.out.println("当前分享图片是" + param); }}public class OrderItemShare { // 下单 public void algorithm(String param) { System.out.println("当前分享图片是" + param); }}public class ShareFactory { public static void main(String[] args) throws Exception { Integer shareType = 1; // 测试业务逻辑 if (shareType.equals(ShareType.SINGLE.getCode())) { SingleItemShare singleItemShare = new SingleItemShare(); singleItemShare.algorithm("单商品"); } else if (shareType.equals(ShareType.MULTI.getCode())) { MultiItemShare multiItemShare = new MultiItemShare(); multiItemShare.algorithm("多商品"); } else if (shareType.equals(ShareType.ORDER.getCode())) { OrderItemShare orderItemShare = new OrderItemShare(); orderItemShare.algorithm("下单"); } else { throw new Exception("未知分享类型"); } // .....省略更多分享场景 } enum ShareType { SINGLE(1, "单商品"), MULTI(2, "多商品"), ORDER(3, "下单"); /** * 场景对应的编码 */ private Integer code; /** * 业务场景描述 */ private String desc; ShareType(Integer code, String desc) { this.code = code; this.desc = desc; } public Integer getCode() { return code; } // 省略 get set 方法 }}
这里大家可以看到每新加一种分享类型,就需要加一次if else 判断,当如果有十几种场景的时候那代码整体就会非常的长,看起来给人的感觉也不是很舒服。文章源自JAVA秀-https://www.javaxiu.com/30601.html
接下来就看看如何用策略模式进行重构:文章源自JAVA秀-https://www.javaxiu.com/30601.html
public interface ShareStrategy { // 定义分享策略执行方法 void shareAlgorithm(String param);}public class OrderItemShare implements ShareStrategy { @Override public void shareAlgorithm(String param) { System.out.println("当前分享图片是" + param); }}// 省略 MultiItemShare以及SingleItemShare策略// 分享工厂public class ShareFactory { // 定义策略枚举 enum ShareType { SINGLE("single", "单商品"), MULTI("multi", "多商品"), ORDER("order", "下单"); // 场景对应的编码 private String code; // 业务场景描述 private String desc; ShareType(String code, String desc) { this.code = code; this.desc = desc; } public String getCode() { return code; } // 省略 get set 方法 } // 定义策略map缓存 private static final Map<String, ShareStrategy> shareStrategies = new HashMap<>(); static { shareStrategies.put("order", new OrderItemShare()); shareStrategies.put("single", new SingleItemShare()); shareStrategies.put("multi", new MultiItemShare()); } // 获取指定策略 public static ShareStrategy getShareStrategy(String type) { if (type == null || type.isEmpty()) { throw new IllegalArgumentException("type should not be empty."); } return shareStrategies.get(type); } public static void main(String[] args) { // 测试demo String shareType = "order"; ShareStrategy shareStrategy = ShareFactory.getShareStrategy(shareType); shareStrategy.shareAlgorithm("order"); // 输出结果:当前分享图片是order }}
这里策略模式就已经改造完了。在client请求端,根本看不到那么多的if else判断,只需要传入对应的策略方式即可,这里我们维护了一个策略缓存map,在直接调用的ShareFactory获取策略的时候就直接是从换种获取策略类对象。文章源自JAVA秀-https://www.javaxiu.com/30601.html
这就已经达到了行为解偶的思想。同时也避免了长串的if else 判断。文章源自JAVA秀-https://www.javaxiu.com/30601.html
优点:文章源自JAVA秀-https://www.javaxiu.com/30601.html
算法策略可以自由实现切换文章源自JAVA秀-https://www.javaxiu.com/30601.html
扩展性好,加一个策略,只需要增加一个类文章源自JAVA秀-https://www.javaxiu.com/30601.html
缺点:文章源自JAVA秀-https://www.javaxiu.com/30601.html
策略类数量多文章源自JAVA秀-https://www.javaxiu.com/30601.html
需要维护一个策略枚举,让别人知道你当前具有哪些策略文章源自JAVA秀-https://www.javaxiu.com/30601.html
总结
以上就讲完了策略模式,整体看上去其实还是比较简单的,还是那句话学习设计模式我们还是要学习每种设计模式的思想,任何一种设计模式存在即合理。当然也不要因为设计模式而设计代码,那样反而得不偿失。文章源自JAVA秀-https://www.javaxiu.com/30601.html
本次分享到这里就结束了,我是敖丙,你知道的越多,你不知道的越多,我们下期见!文章源自JAVA秀-https://www.javaxiu.com/30601.html

评论