设计模式应用之策略模式

简介: 当业务需求涉及到很多的分支逻辑时,过多的if-else或者过多的switch代码显得很不简洁,而且当我们修改某一分支逻辑时,要改动的很多,比如现在某一分支不要了,就要把这个if条件删除掉,这样是很不好的,这个时候,我们想到了策略模式,替换掉过多的if-else或者switch语句。

一、实际开发痛点

当业务需求涉及到很多的分支逻辑时,过多的if-else或者过多的switch代码显得很不简洁,而且当我们修改某一分支逻辑时,要改动的很多,比如现在某一分支不要了,就要把这个if条件删除掉,这样是很不好的,这个时候,我们想到了策略模式,替换掉过多的if-else或者switch语句。

二、什么是策略模式

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

三、实际应用

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 {
    @Resource
    private CommonService commonService;
    @Override
    protected Boolean handler(JSONObject json) {
        JSONObject data = json.getJSONObject("data");
        String wId = data.getString("wId");
        String v1 = data.getString("v1");
        String v2 = data.getString("v2");
        Integer type = data.getInteger("scene");
        Map<String, Object> param = 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、调用抽象方法
第一步,先把抽象类注入,这里以map的方式注入,key为beanName,值为具体的实现类。

@Resource
    private Map<String, AbstractMsgCallBackHandler> abstractMsgCallBackHandlerMap;

第二步、通过类型获取beanName,从枚举中获取value

String beanName = MsgCallBackEnum.getBeanName(messageType);

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

AbstractMsgCallBackHandler abstractMsgCallBackHandler = abstractMsgCallBackHandlerMap.get(beanName);

第四步、调用抽象类抽象方法,会自动指向实现类

abstractMsgCallBackHandler.process(json);

整体的代码大概是这样的:

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

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

四、总结

  1. 何时使用
    一个系统有许多类,而区分它们的只是他们直接的行为时
  2. 方法
    将这些算法封装成一个一个的类,任意的替换
  3. 优点
    算法可以自由切换
    避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
    扩展性良好,增加一个策略只需实现接口即可
  4. 缺点
    策略类数量会增多,每个策略都是一个类,复用的可能性很小
    所有的策略类都需要对外暴露
  5. 使用场景
    多个类只有算法或行为上稍有不同的场景
    算法需要自由切换的场景
    需要屏蔽算法规则的场景
目录
相关文章
|
5天前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
23 1
|
9天前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
18 2
|
23天前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
43 2
|
5天前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
19 1
|
2月前
|
设计模式 PHP 开发者
PHP中的设计模式:桥接模式的解析与应用
在软件开发的浩瀚海洋中,设计模式如同灯塔一般,为开发者们指引方向。本文将深入探讨PHP中的一种重要设计模式——桥接模式。桥接模式巧妙地将抽象与实现分离,通过封装一个抽象的接口,使得实现和抽象可以独立变化。本文将阐述桥接模式的定义、结构、优缺点及其应用场景,并通过具体的PHP示例代码展示如何在实际项目中灵活运用这一设计模式。让我们一起走进桥接模式的世界,感受它的魅力所在。
|
2月前
|
设计模式 测试技术 持续交付
架构视角下的NHibernate:设计模式与企业级应用考量
【10月更文挑战第13天】随着软件开发向更复杂、更大规模的应用转变,数据访问层的设计变得尤为重要。NHibernate作为一个成熟的对象关系映射(ORM)框架,为企业级.NET应用程序提供了强大的支持。本文旨在为有一定经验的开发者提供一个全面的指南,介绍如何在架构层面有效地使用NHibernate,并结合领域驱动设计(DDD)原则来构建既强大又易于维护的数据层。
38 2
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文通过游泳运动员的案例,介绍策略模式及其在Kotlin中的改良应用,利用高阶函数简化代码结构,提高灵活性。
32 3
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文介绍策略模式在Kotlin中的应用,通过游泳运动员的例子,展示如何使用接口和高阶函数实现策略模式,使代码更简洁、灵活。
29 2
|
2月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践###
【10月更文挑战第18天】 本文深入探讨了Python编程中设计模式的应用与实践,通过简洁明了的语言和生动的实例,揭示了设计模式在提升代码可维护性、可扩展性和重用性方面的关键作用。文章首先概述了设计模式的基本概念和重要性,随后详细解析了几种常用的设计模式,如单例模式、工厂模式、观察者模式等,在Python中的具体实现方式,并通过对比分析,展示了设计模式如何优化代码结构,增强系统的灵活性和健壮性。此外,文章还提供了实用的建议和最佳实践,帮助读者在实际项目中有效运用设计模式。 ###
19 0