设计模式应用之策略模式

简介: 当业务需求涉及到很多的分支逻辑时,过多的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. 使用场景
    多个类只有算法或行为上稍有不同的场景
    算法需要自由切换的场景
    需要屏蔽算法规则的场景
目录
相关文章
|
6月前
|
设计模式 算法 搜索推荐
Java 设计模式之策略模式:灵活切换算法的艺术
策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。
1530 35
|
7月前
|
设计模式 人工智能 算法
基于多设计模式的状态扭转设计:策略模式与责任链模式的实战应用
接下来,我会结合实战案例,聊聊如何用「策略模式 + 责任链模式」构建灵活可扩展的状态引擎,让抽奖系统的状态管理从「混乱战场」变成「有序流水线」。
|
8月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
11月前
|
设计模式 算法 Java
设计模式觉醒系列(04)策略模式|简单工厂模式的升级版
本文介绍了简单工厂模式与策略模式的概念及其融合实践。简单工厂模式用于对象创建,通过隐藏实现细节简化代码;策略模式关注行为封装与切换,支持动态替换算法,增强灵活性。两者结合形成“策略工厂”,既简化对象创建又保持低耦合。文章通过支付案例演示了模式的应用,并强调实际开发中应根据需求选择合适的设计模式,避免生搬硬套。最后推荐了JVM调优、并发编程等技术专题,助力开发者提升技能。
|
11月前
|
设计模式 算法 搜索推荐
【设计模式】【行为型模式】策略模式(Strategy)
一、入门 什么是策略模式? 策略模式是一种行为设计模式,允许在运行时选择算法或行为。它将算法封装在独立的类中,使得它们可以互换,而不影响客户端代码。 为什么需要策略模式? 策略模式的主要目的是解决算法
237 14
|
设计模式 算法 开发者
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
504 8
「全网最细 + 实战源码案例」设计模式——策略模式
|
设计模式 存储 缓存
前端必须掌握的设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,旨在将多分支复杂逻辑解耦。每个分支类只关心自身实现,无需处理策略切换。它避免了大量if-else或switch-case代码,符合开闭原则。常见应用场景包括表单验证、风格切换和缓存调度等。通过定义接口和上下文类,策略模式实现了灵活的逻辑分离与扩展。例如,在国际化需求中,可根据语言切换不同的词条包,使代码更加简洁优雅。总结来说,策略模式简化了多条件判断,提升了代码的可维护性和扩展性。
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
177 1
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
252 2