400-035-6699
当前位置: 首页 » 技术支持 » 博文资讯 »

\"策略模式详解:Java中的最佳实践与应用案例\"

在编程中,我们经常会遇到需要根据不同场景选择不同算法的情况。例如,在处理用户输入时,可能需要根据用户的不同输入选择不同的处理方式。这时,我们就可以使用策略模式来实现这种功能。
策略模式是一种设计模式,它定义了一系列算法类,将每一个算法封装起来,并让它们可以相互替换。这样,算法就可以独立于使用它的客户而变化。简单来说,策略模式就是针对不同的场景,使用不同的策略进行处理。
策略模式的优点主要有以下几点:
1. 算法可以自由切换:我们可以根据不同的需求选择不同的策略,这样可以灵活地应对各种情况。
2. 避免使用多重条件判断:如果使用传统的if-else语句来实现,可能会出现很多复杂的条件判断,而使用策略模式可以避免这种情况,使代码更加清晰。
3. 扩展性良好:如果需要添加新的策略,只需要添加一个新的策略类,不需要修改其他代码。
当然,策略模式也有一些缺点:
1. 策略类会增多:随着策略的增加,策略类的数量也会增加,可能会增加代码的复杂度。
2. 所有策略类都需要对外暴露:由于所有的策略都需要对外暴露,可能会导致代码的耦合度较高。
使用场景:
1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2. 一个系统需要动态地在几种算法中选择一种。
3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
接下来,我们通过一个简单的例子来了解策略模式的使用方法
场景:假设我们有一个任务管理器,它可以执行三种类型的任务:计算任务、存储任务和打印任务。每种任务都有其特定的执行方式。我们可以使用策略模式来实现这个功能。
首先,我们定义一个策略接口:
public interface TaskStrategy { void execute(); }
然后,我们定义三种不同的策略类,实现策略接口:
public class CalculationTaskStrategy implements TaskStrategy { @Override public void execute() { System.out.println("执行计算任务"); } }
public class StorageTaskStrategy implements TaskStrategy { @Override public void execute() { System.out.println("执行存储任务"); } }
public class PrintTaskStrategy implements TaskStrategy { @Override public void execute() { System.out.println("执行打印任务"); } }
最后,我们定义一个上下文类,用于使用策略:
public class TaskContext { private TaskStrategy strategy;
public TaskContext(TaskStrategy strategy) { this.strategy = strategy; }
public void executeTask() { strategy.execute(); } }
通过以上代码,我们实现了策略模式。当我们需要执行不同的任务时,只需要创建不同的策略对象,并传递给上下文对象即可。这样,我们的代码变得更加灵活和可扩展。
在实际开发中,策略模式被广泛应用于各种场景,例如:
1. 优惠券计算:根据不同的优惠券类型,选择不同的计算策略。
2. 订单支付:根据不同的支付方式,选择不同的支付策略。
3. 消息解析:根据不同的消息类型,选择不同的解析策略。
总之,策略模式是一种非常有用的设计模式,可以帮助我们更好地管理算法,使代码更加灵活和可扩展。在开发过程中,我们应该根据实际需求合理使用策略模式,以提高代码质量和开发效率。

什么是策略模式

官话: 策略模式(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);
        }
    }
}

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

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

小结

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

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

【限时免费】一键获取网络规划系统模板+传输架构设计+连通性评估方案

相关文章

服务电话:
400-035-6699
企服商城