文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

设计模式系列之策略模式

2024-12-03 03:20

关注

最近有一个学妹在跟我沟通如何有效的去避免代码中一长串的if else判断或者switch条件判断?针对更多的回答就是合理的去使用设计来规避这个问题。

在设计模式中,可以使用工厂模式或者策略模式来处理这类问题,之前已经分享了工厂模式,感兴趣的同学可以去复习一下。

设计模式系列往期文章:

那么工厂模式和策略模式有什么区别呢?

本次就来具体聊聊策略模式它是如何做到行为解耦

大纲

定义

什么是策略模式?它的原理实现是怎么样的?

定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。以上定义来自设计模式之美

感觉有点抽象?那就来看一张结构图吧

这么看结构其实还是不复杂的,而且跟状态模式类似。

那么这个代码怎么实现?

举个例子,汽车大家肯定都不陌生,愿大家早日完成汽车梦,汽车的不同档(concreteStrategy)就好比不同的策略,驾驶者选择几档则汽车按几档的速度前进,整个选择权在驾驶者(context)手中。

  1. public interface GearStrategy { 
  2.  
  3.     // 定义策略执行方法 
  4.     void algorithm(String param); 

首先还是先定义抽象策略

这里是用接口的形式,还有一种方式可以用抽象方法abstract来写也是一样的。具体就看大家自己选择了。

  1. public abstract class GearStrategyAbstract { 
  2.  // 定义策略执行方法 
  3.  abstract void algorithm(String param); 

  1. public class GearStrategyOne implements GearStrategy { 
  2.  
  3.     @Override 
  4.     public void algorithm(String param) { 
  5.         System.out.println("当前档位" + param); 
  6.     } 

其次定义具体档位策略,实现algorithm方法。

  1. public class Context { 
  2.   // 缓存所有的策略,当前是无状态的,可以共享策略类对象 
  3.     private static final Map strategies = new HashMap<>(); 
  4.  
  5.     // 第一种写法 
  6.     static { 
  7.         strategies.put("one", new GearStrategyOne()); 
  8.     } 
  9.  
  10.     public static GearStrategy getStrategy(String type) { 
  11.         if (type == null || type.isEmpty()) { 
  12.             throw new IllegalArgumentException("type should not be empty."); 
  13.         } 
  14.         return strategies.get(type); 
  15.     } 
  16.  
  17.     // 第二种写法 
  18.     public static GearStrategy getStrategySecond(String type) { 
  19.         if (type == null || type.isEmpty()) { 
  20.             throw new IllegalArgumentException("type should not be empty."); 
  21.         } 
  22.         if (type.equals("one")) { 
  23.             return new GearStrategyOne(); 
  24.         } 
  25.         return null
  26.     } 
  27.  
  28.  
  29.     public static void main(String[] args) { 
  30.         // 测试结果 
  31.         GearStrategy strategyOne = Context.getStrategy("one"); 
  32.         strategyOne.algorithm("1档"); 
  33.          // 结果:当前档位1档 
  34.         GearStrategy strategyTwo = Context.getStrategySecond("one"); 
  35.         strategyTwo.algorithm("1档"); 
  36.         // 结果:当前档位1档 
  37.     } 
  38.  

最后就是实现运行时环境(Context),你可以定义成StrategyFactory,但都是一个意思。

在main方法里面的测试demo,可以看到通过不同的type类型,可以实现不同的策略,这就是策略模式主要思想。

在Context里面定义了两种写法:

框架的应用

策略模式在框架中也在一个很常见的地方体现出来了,而且大家肯定都有使用过。

那就是JDK中的线程池ThreadPoolExecutor

首先都是类似于这样定义一个线程池,里面实现线程池的异常策略。

这个线程池的异常策略就是用的策略模式的思想。

在源码中有RejectedExecutionHandler这个抽象异常策略接口,同时它也有四种拒绝策略。关系图如下:

这就是在框架中的体现了,根据自己的业务场景,合理的选择线程池的异常策略。

业务改造举例

在真实的业务场景中策略模式也还是应用很多的。

在社交电商中分享商品是一个很重要的环节,假设现在要我们实现一个分享图片功能,比如当前有 单商品、多商品、下单、会场、邀请、小程序链接等等多种分享场景。

针对上线这个流程图先用if else语句做一个普通业务代码判断,就像下面的这中方式:

  1. public class SingleItemShare { 
  2.     // 单商品 
  3.     public void algorithm(String param) { 
  4.         System.out.println("当前分享图片是" + param); 
  5.     } 
  6. public class MultiItemShare { 
  7.     // 多商品 
  8.     public void algorithm(String param) { 
  9.         System.out.println("当前分享图片是" + param); 
  10.     } 
  11. public class OrderItemShare { 
  12.     // 下单 
  13.     public void algorithm(String param) { 
  14.         System.out.println("当前分享图片是" + param); 
  15.     } 
  16. public class ShareFactory { 
  17.  
  18.     public static void main(String[] args) throws Exception { 
  19.         Integer shareType = 1; 
  20.        // 测试业务逻辑 
  21.         if (shareType.equals(ShareType.SINGLE.getCode())) { 
  22.             SingleItemShare singleItemShare = new SingleItemShare(); 
  23.             singleItemShare.algorithm("单商品"); 
  24.         } else if (shareType.equals(ShareType.MULTI.getCode())) { 
  25.             MultiItemShare multiItemShare = new MultiItemShare(); 
  26.             multiItemShare.algorithm("多商品"); 
  27.         } else if (shareType.equals(ShareType.ORDER.getCode())) { 
  28.             OrderItemShare orderItemShare = new OrderItemShare(); 
  29.             orderItemShare.algorithm("下单"); 
  30.         } else { 
  31.             throw new Exception("未知分享类型"); 
  32.         } 
  33.         // .....省略更多分享场景 
  34.     } 
  35.  
  36.     enum ShareType { 
  37.         SINGLE(1, "单商品"), 
  38.         MULTI(2, "多商品"), 
  39.         ORDER(3, "下单"); 
  40.          
  41.         private Integer code; 
  42.          
  43.         private String desc
  44.         ShareType(Integer code, String desc) { 
  45.             this.code = code; 
  46.             this.desc = desc
  47.         } 
  48.         public Integer getCode() { 
  49.             return code; 
  50.         } 
  51.        // 省略 get set 方法 
  52.     } 

这里大家可以看到每新加一种分享类型,就需要加一次if else 判断,当如果有十几种场景的时候那代码整体就会非常的长,看起来给人的感觉也不是很舒服。

接下来就看看如何用策略模式进行重构:

  1. public interface ShareStrategy { 
  2.     // 定义分享策略执行方法 
  3.     void shareAlgorithm(String param); 
  4.  
  5. public class OrderItemShare implements ShareStrategy { 
  6.     @Override 
  7.     public void shareAlgorithm(String param) { 
  8.         System.out.println("当前分享图片是" + param); 
  9.     } 
  10.  
  11. // 省略 MultiItemShare以及SingleItemShare策略 
  12.  
  13. // 分享工厂 
  14. public class ShareFactory { 
  15.   // 定义策略枚举 
  16.     enum ShareType { 
  17.         SINGLE("single""单商品"), 
  18.         MULTI("multi""多商品"), 
  19.         ORDER("order""下单"); 
  20.         // 场景对应的编码 
  21.         private String code; 
  22.         
  23.         // 业务场景描述 
  24.         private String desc
  25.         ShareType(String code, String desc) { 
  26.             this.code = code; 
  27.             this.desc = desc
  28.         } 
  29.         public String getCode() { 
  30.             return code; 
  31.         } 
  32.        // 省略 get set 方法 
  33.     } 
  34.   // 定义策略map缓存 
  35.     private static final Map shareStrategies = new       HashMap<>(); 
  36.     static { 
  37.         shareStrategies.put("order", new OrderItemShare()); 
  38.         shareStrategies.put("single", new SingleItemShare()); 
  39.         shareStrategies.put("multi", new MultiItemShare()); 
  40.     } 
  41.     // 获取指定策略 
  42.     public static ShareStrategy getShareStrategy(String type) { 
  43.         if (type == null || type.isEmpty()) { 
  44.             throw new IllegalArgumentException("type should not be empty."); 
  45.         } 
  46.         return shareStrategies.get(type); 
  47.     } 
  48.   
  49.     public static void main(String[] args) { 
  50.         // 测试demo 
  51.         String shareType = "order"
  52.         ShareStrategy shareStrategy = ShareFactory.getShareStrategy(shareType); 
  53.         shareStrategy.shareAlgorithm("order"); 
  54.         // 输出结果:当前分享图片是order 
  55.     } 

这里策略模式就已经改造完了。在client请求端,根本看不到那么多的if else判断,只需要传入对应的策略方式即可,这里我们维护了一个策略缓存map,在直接调用的ShareFactory获取策略的时候就直接是从换种获取策略类对象。

这就已经达到了行为解偶的思想。同时也避免了长串的if else 判断。

优点:

缺点:

总结

以上就讲完了策略模式,整体看上去其实还是比较简单的,还是那句话学习设计模式我们还是要学习每种设计模式的思想,任何一种设计模式存在即合理。当然也不要因为设计模式而设计代码,那样反而得不偿失。

 

来源:三太子敖丙内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯