0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是策略模式

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-08 14:15 次阅读

什么是策略模式

官话: 策略模式(Strategy Pattern): 定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化。

简单理解就是,针对不同的场景,使用不同的策略进行处理。

优点

  1. 算法可以自由切换。
  2. 避免使用多重条件判断。
  3. 扩展性良好。

缺点

  1. 策略类会增多。
  2. 所有策略类都需要对外暴露。

使用场景

  1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
  2. 一个系统需要动态地在几种算法中选择一种。
  3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

结构图

图片
策略模式结构图

策略模式的简单示例

场景:最近太热了,想要降降温,有什么办法呢

首先,定义一个降温策略的接口

public interface CoolingStrategy {

    /**
     * 处理方式
     */
    void handle();

}

定义3种降温策略;实现策略接口

public class IceCoolingStrategy implements CoolingStrategy {
    @Override
    public void handle() {
        System.out.println("使用冰块降温");
    }
}
public class FanCoolingStrategy implements CoolingStrategy {

    @Override
    public void handle() {
        System.out.println("使用风扇降温");
    }
}
public class AirConditionerCoolingStrategy implements CoolingStrategy {
    @Override
    public void handle() {
        System.out.println("使用空调降温");
    }
}

定义一个降温策略的上下文

public class CoolingStrategyContext {

    private final CoolingStrategy strategy;

    public CoolingStrategyContext(CoolingStrategy strategy) {
        this.strategy = strategy;
    }

    public void coolingHandle() {
        strategy.handle();
    }

}

测试

public class Main {
    public static void main(String[] args) {
        
        CoolingStrategyContext context = new CoolingStrategyContext(new FanCoolingStrategy());
        context.coolingHandle();

        context = new CoolingStrategyContext(new AirConditionerCoolingStrategy());
        context.coolingHandle();

        context = new CoolingStrategyContext(new IceCoolingStrategy());
        context.coolingHandle();
    }
}

运行结果:

使用风扇降温
使用空调降温
使用冰块降温

以上就是一个策略模式的简单实现

策略模式的项目实战

场景

以我自己在工作中遇到的场景为例,《企业微信会话存档》功能,获取各种格式的消息内容,进行解析并保存数据。这里只针对消息处理的功能模块,其他关于《企业微信会话存档》的功能,有时间整理一下再发出来。

企业微信会话聊天会产生如下多种消息,在SpringBoot项目中应该如何使用策略模式来完成消息的解析呢?

图片
企业微信消息格式

获取会话内容 - API 看API内容,数据都是json格式。思考应该如何处理:

  1. 首先,既然要解析各种数据,而每种数据格式结构都不一样,那么就需要先根据每种消息格式定义各自的对象,然后根据不同的需求,将json格式处理成pojo对象;
  2. 根据场景,需要定义两个策略接口,一个是针对普通的文本格式消息的策略,另一个则是需要处理文件格式消息的策略;
  3. 定义策略处理上下文操作类,用于使用策略
  4. 每种消息,都会有一些相同的数据,比如发送人、接收人、消息类型等;根据消息类型的不同,使用 key-value 的方式,让调用者确定应该使用哪个策略来处理数据

因为格式太多,这里只使用两个格式作为例子

实现

两个策略接口

public interface Strategy {
    /**
     * 处理会话存档的内容
     *
     * @param content json格式的消息内容
     * @return 结果
     */
    < T > T handleContent(String content);
}
public interface MediaStrategy {
    /**
     * 处理会话存档媒体内容
     *
     * @param msgData 消息内容
     */
    < T > void handleMedia(T msgData);
}

策略的具体实现(伪代码)

@Component("link")
public class LinkStrategy implements Strategy {

    @Override
    public LinkPO handleContent(String content) {
        // JSON 转换为具体对象
        LinkWrapDTO linkWrapDTO = JacksonUtils.json2Obj(content, LinkWrapDTO.class);
        // 将对象处理成业务需要的格式
        return Convert.convert(LinkPO.class, linkWrapDTO);
    }
}
@Component("image")
public class ImageStrategy implements Strategy, MediaStrategy {

    @Autowired
    private IMsgFileService msgFileService;

    @Override
    public ImagePO handleContent(String content) {
        // JSON 转换为具体对象
        ImageWrapDTO imageWrapDTO = JacksonUtils.json2Obj(content, ImageWrapDTO.class);
        // 将对象处理成业务需要的格式
        return Convert.convert(ImagePO.class,imageWrapDTO);
    }

    @Override
    public < T > void handleMedia(T msgData) {
        // 将数据格式转换为具体实现的数据格式
        ImagePO imagePo = Convert.convert(ImagePO.class, msgData);
        // 调用文件服务,进一步处理文件
        msgFileService.newFileTask(imagePo.getImage().getSdkfileid(),
                imagePo.getMsgid() + ".jpg", imagePo.getMsgid(), imagePo.getSeq(),
                imagePo.getImage().getFilesize(), imagePo.getImage().getMd5sum(), MessageEnum.IMAGE);
    }
}

策略上下文

@Component
public class StrategyContext {

    @Resource
    Map< String, Strategy > strategys = new ConcurrentHashMap<  >();

    @Resource
    Map< String, MediaStrategy > mediaStrategys = new ConcurrentHashMap<  >();

    public Strategy getStrategy(String component) {
        return strategys.get(component);
    }

    public MediaStrategy getMediaStrategy(String component) {
        return mediaStrategys.get(component);
    }
}

使用方式(伪代码)

public class MsgService {
   @Resource
    private StrategyContext strategyContext;
    
    public void handlerMessage() {
        // 请求api获取消息的json
        json = api();
        // 转为通用格式对象
        basePo = JsonUtils.json2Obj(json, BasePO.class);
        // 选取不同的策略
        Strategy strategy = strategyContext.getStrategy(basePo.getMsgType());
        // 进行处理
        strategy.handleContent(json);
        // 关于文件类消息的处理
        MediaStrategy mediaStrategy = strategyContext.getMediaStrategy(basePo.getMsgtype());
        if (null != mediaStrategy) {
            mediaStrategy.handleMedia(basePo);
        }
    }
}

以上就是策略模式的一种实现方式;

使用策略模式来处理不同格式的消息,虽然多了很多策略类,但是让整个功能模块的代码变得清晰,松耦合,而且很容易扩展和修改,并不会影响其他流程。

小结

从以上的例子很明显的可以看出,策略模式的灵活性;如果此时企业微信提供了一种新的消息格式,那么根本无需修改之前的代码,只需要再写一个新的类,实现消息处理策略的接口,重写处理方法即可;

了解策略模式的优点和缺点,合理的使用策略模式,会让你的代码更加的整洁优雅。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8422

    浏览量

    150665
  • 数据
    +关注

    关注

    8

    文章

    6786

    浏览量

    88705
  • 算法
    +关注

    关注

    23

    文章

    4585

    浏览量

    92443
  • API
    API
    +关注

    关注

    2

    文章

    1470

    浏览量

    61725
收藏 人收藏

    评论

    相关推荐

    76 JavaScrip 面向对象编程模式实践 策略模式

    前端javascript
    小凡
    发布于 :2022年08月28日 17:28:44

    #硬声创作季 设计模式:谈谈你对策略模式的理解

    python
    Mr_haohao
    发布于 :2022年10月16日 13:06:10

    关于LVOOP设计模式的框架问题?

    1. 请问目前的很多设计模式,比如简单工厂模式策略模式之类的,labview是不是没有框架,需要自己手工去实现?2. labview的actor framework是不是目前labv
    发表于 08-07 23:14

    LABVIEW OOP 策略模式

    本帖最后由 meiyoudiandian 于 2020-5-18 21:59 编辑 《大话设计模式》这本书还是挺不错的,不知道出于什么原因,突然心血来潮,就想跟着写写。一章一章慢慢来,大家一同讨论,共同进步。没有目的,没有初衷,没有情怀,只是素人。2020/05/18
    发表于 05-18 21:57

    C语言的策略模式提高了程序的可维护性和扩展性

    设计模式,必定会在严谨地维护类层次上造成非常繁琐和臃肿的代码。这是因为C++/java等自带一套面向对象的工具,而C语言要在代码设计中,不断地根据实际情况来创造面向对象的工具。 因此对于文章的内容,请大家主要关注、体会设计模式本身,更
    发表于 06-24 16:29 1138次阅读

    不会有人不知道怎么优雅的替换if-else语句吧

    三板斧手段: 优先判断条件,条件不满足的,逻辑及时中断返回; 融入策略模式策略模式+工厂+单例模式,锦上添花; 接
    的头像 发表于 07-28 15:46 1386次阅读
    不会有人不知道怎么优雅的替换if-else语句吧

    设计模式 考试题+答案

    (Decorator) B策略模式(Strategy)C桥接模式(Bridge) D观察者模式(Observer)转存失败重...
    发表于 11-07 10:20 39次下载
    设计<b class='flag-5'>模式</b> 考试题+答案

    Linux下CPU的手动频率设定 CPU电源策略模式

    http://www.51testing.com/html/20/n-3723920.html
    发表于 01-12 11:25 1次下载
    Linux下CPU的手动频率设定 CPU电源<b class='flag-5'>策略</b><b class='flag-5'>模式</b>

    设计模式最佳实践探索—策略模式

    根据不同的应用场景与意图,设计模式主要分为创建型模式、结构型模式和行为型模式三类。本文主要探索行为型模式中的
    的头像 发表于 10-31 14:24 903次阅读

    为什么我不再推荐枚举策略模式

    我们可以看到经典方法,创建了一个接口、三个策略类,还是比较啰嗦的。调用类的实现也待商榷,新增一个策略类还要修改榜单实例(可以用抽象工厂解决,但是复杂度又上升了)。加之我们有更好的选择,所以此处不再推荐经典策略
    的头像 发表于 04-14 10:52 1949次阅读

    高频使用的几种设计模式

    策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的的客户。这个策略模式的定义是不是有点抽象呢?那
    的头像 发表于 05-08 09:57 919次阅读
    高频使用的几种设计<b class='flag-5'>模式</b>

    介绍嵌入式C语言中策略模式的基本原理和实现方法

    嵌入式系统常常需要对不同的输入采取不同的行为,例如按下按钮后的操作、传感器读数后的处理、接收到的通信数据的解析等等。
    发表于 05-20 17:27 860次阅读

    设计模式行为型:策略模式

    策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式
    的头像 发表于 06-07 11:18 616次阅读
    设计<b class='flag-5'>模式</b>行为型:<b class='flag-5'>策略</b><b class='flag-5'>模式</b>

    迭代模式在UVM中的应用有哪些

    行为型设计模式数量较多,上一篇介绍了模板模式策略模式,下面对迭代模式进行介绍,挖掘其在UVM中的应用。
    的头像 发表于 08-14 17:15 565次阅读
    迭代<b class='flag-5'>模式</b>在UVM中的应用有哪些

    如何通过策略模式简化if-else

    相信大家日常开发中会经常写各种分支判断语句,比如 if-else ,当分支较多时,代码看着会比较臃肿,那么如何优化呢? 1、什么是策略模式? Define a family
    的头像 发表于 10-08 16:08 679次阅读
    如何通过<b class='flag-5'>策略</b><b class='flag-5'>模式</b>简化if-else