热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java中二十三种设计模式——策略模式(初识)

1.什么是策略模式策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等

1.什么是策略模式

策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。 再比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。 策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。

 

2.使用场景

1、业务场景 现在需要接收来自某系统的回调,消息回调会有很多类型,比如私聊文本消息、私聊图片消息、新好友申请、私聊语音消息等,每一种消息类型,对应不同的逻辑处理,我们最开始是想直接if-else或者switch,走不同的分支逻辑搞定,但是这样扩展性不好,不易维护,这时我们想到了策略模式。 2、定义枚举类 枚举类存放各种回调类型,值代表的是具体实现类的类名,首字母这里小写。通过key就能得到对应的类beaName。

@Getter
public enum MsgCallBackEnum {//新好友申请NEWFRIEND_MSG_CALL_BACK(0, "newFriendMsgCallBackHandler"),//添加好友成功ADDFRIENDSUCCESS_MSG_CALL_BACK(16, "addfriendSuccessMsgCallBackHandler"),//私聊文本消息PRIVATECHATTEXT_MSG_CALL_BACK(5, "privateChatTextMsgCallBackHandler"),//私聊图片消息PRIVATECHATIMAGE_MSG_CALL_BACK(6, "privateChatImageMsgCallBackHandler"),//私聊视频消息privateChatVIDEO_MSG_CALL_BACK(7, "privateChatVideoMsgCallBackHandler"),//私聊语音消息PRIVATECHATVOICE_MSG_CALL_BACK(8, "privateChatVoiceMsgCallBackHandler");private Integer type;private String beanName;MsgCallBackEnum(Integer type, String beanName) {this.type = type;this.beanName = beanName;}public static String getBeanName(Integer type) throws BusinessException {for (MsgCallBackEnum msgCallBackStrategyEnum : MsgCallBackEnum.values()) {if (msgCallBackStrategyEnum.type.equals(type)) {return msgCallBackStrategyEnum.getBeanName();}}return null;}}

3、定义抽象类 抽象类定义抽象方法handler,每一种逻辑处理类只需要继承这个抽象类就可以了。

public abstract class AbstractMsgCallBackHandler {public final Boolean process(JSONObject json) {return this.handler(json);}/*** 处理相应逻辑** @param json* @return*/protected abstract Boolean handler(JSONObject json);
}

4、定义实现类 实现类具体处理业务逻辑,继承抽象类

@Component
@Slf4j
public class NewFriendMsgCallBackHandler extends AbstractMsgCallBackHandler {&#64;Resourceprivate CommonService commonService;&#64;Overrideprotected Boolean handler(JSONObject json) {JSONObject data &#61; json.getJSONObject("data");String wId &#61; data.getString("wId");String v1 &#61; data.getString("v1");String v2 &#61; data.getString("v2");Integer type &#61; data.getInteger("scene");Map param &#61; new HashMap<>();param.put("wId", wId);param.put("v1", v1);param.put("v2", v2);param.put("type", type);commonService.commonSendPost(param, UrlConstant.WK_ACCEPTUSER_URL);return Boolean.TRUE;}
}

5、调用抽象方法 第一步&#xff0c;先把抽象类注入&#xff0c;这里以map的方式注入&#xff0c;key为beanName&#xff0c;值为具体的实现类。

&#64;Resourceprivate Map abstractMsgCallBackHandlerMap;

第二步、通过类型获取beanName&#xff0c;从枚举中获取value

String beanName &#61; MsgCallBackEnum.getBeanName(messageType);

第三步、通过beanName获取抽象类

AbstractMsgCallBackHandler abstractMsgCallBackHandler &#61; abstractMsgCallBackHandlerMap.get(beanName);

 第四步、调用抽象类抽象方法&#xff0c;会自动指向实现类

abstractMsgCallBackHandler.process(json);

 整体的代码大概是这样的&#xff1a;

&#64;Slf4j
&#64;RestController
&#64;RequestMapping("/callBack")
public class CallBackController {&#64;Resourceprivate WxAdminService wxAdminService;&#64;Resourceprivate Map abstractMsgCallBackHandlerMap;/*** 消息接收服务地址** &#64;param msg* &#64;return*/&#64;TokenNeedless&#64;PostMapping("/getMsgCallBack")public Result getMsgCallBack(&#64;RequestBody String msg) {JSONObject json &#61; JSONObject.parseObject(msg);//消息类型Integer messageType &#61; json.getInteger("messageType");log.info("getMsgCallBack:{}", msg);String beanName &#61; MsgCallBackEnum.getBeanName(messageType);AbstractMsgCallBackHandler abstractMsgCallBackHandler &#61; abstractMsgCallBackHandlerMap.get(beanName);if (abstractMsgCallBackHandler &#61;&#61; null) {return Result.ok();}Boolean process &#61; abstractMsgCallBackHandler.process(json);log.info("getMsgCallBack_process:{}", process);return Result.ok();}
}

这样以后有新的类型&#xff0c;直接写一个实现抽象类的类就可以了&#xff0c;代码藕和度下降很多。

四、总结


  1. 何时使用 一个系统有许多类&#xff0c;而区分它们的只是他们直接的行为时
  2. 方法 将这些算法封装成一个一个的类&#xff0c;任意的替换
  3. 优点 算法可以自由切换 避免使用多重条件判断&#xff08;如果不用策略模式我们可能会使用多重条件语句&#xff0c;不利于维护&#xff09; 扩展性良好&#xff0c;增加一个策略只需实现接口即可
  4. 缺点 策略类数量会增多&#xff0c;每个策略都是一个类&#xff0c;复用的可能性很小 所有的策略类都需要对外暴露
  5. 使用场景 多个类只有算法或行为上稍有不同的场景 算法需要自由切换的场景 需要屏蔽算法规则的场景

 


推荐阅读
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
author-avatar
ian
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有