策略模式详解

devtools/2025/1/12 3:06:53/

策略模式(Strategy Pattern)是一种常用的行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换使用。策略模式让算法的变化独立于使用算法的客户。下面对策略模式进行详细讲解:
一、角色
1.  环境类(Context)
•  它是客户端与策略类交互的接口,它持有一个策略类的引用。环境类可以根据客户端的要求调用相应的策略方法。例如,在一个音乐播放器软件中,环境类可以是MediaPlayer类,它持有一个音频解码策略的引用。当用户选择不同的音频格式(如MP3、WAV等)播放时,MediaPlayer类会根据选择的格式调用相应的解码策略。
•  环境类通常提供一个接口,让客户端能够设置或更改策略。比如在上面的音乐播放器例子中,MediaPlayer类可以提供一个setAudioDecoder(IAudioDecoder decoder)方法,客户端可以通过这个方法来设置不同的音频解码策略。
2.  抽象策略类(Strategy)
•  它是一个抽象类或接口,用于声明所有支持的操作,定义了具体的策略类必须实现的接口。在音频解码的例子中,IAudioDecoder接口就是抽象策略类,它声明了一个decode()方法,所有具体的音频解码策略类都需要实现这个方法。
•  抽象策略类可以定义一些通用的方法或属性,这些方法或属性可以被具体的策略类继承或使用。例如,IAudioDecoder接口可以定义一些通用的错误处理方法,具体的解码策略类在解码过程中遇到错误时可以调用这些方法。
3.  具体策略类(ConcreteStrategy)
•  它实现了抽象策略类所定义的接口,提供具体算法的实现。在音频解码场景中,MP3Decoder类和WAVDecoder类就是具体策略类,它们分别实现了IAudioDecoder接口中的decode()方法,用于解码MP3格式和WAV格式的音频文件。
•  具体策略类可以根据不同的算法需求,实现不同的逻辑。比如MP3Decoder类在解码MP3文件时,会采用特定的MP3解码算法,而WAVDecoder类则采用WAV格式的解码算法。
二、优点
1.  算法可替换性
•  策略模式使得算法可以在运行时动态替换。在实际应用中,当需要改变算法时,只需更改环境类中策略对象的引用即可。例如,在一个图形绘制软件中,如果用户想要改变图形的绘制算法(如从简单的线条绘制算法替换为复杂的阴影渲染算法),只需在环境类中将策略对象从SimpleLineDrawStrategy替换为ShadowRenderStrategy,而不需要修改环境类的其他代码。
2.  算法独立性
•  策略模式将算法从客户端代码中分离出来,使得算法的修改不会影响到使用算法的客户端。比如在电商系统中,订单的优惠计算策略可能会随着促销活动的变化而变化。使用策略模式,当优惠计算算法改变时,只需修改具体的优惠计算策略类,而订单处理的客户端代码(如订单结算模块)不需要改动,从而降低了系统的耦合度。
3.  扩展性好
•  增加新的策略类非常方便,不需要修改原有代码。只要新的策略类实现了抽象策略类的接口,就可以将其添加到系统中。例如,在一个文本编辑器中,如果要增加一种新的文本格式化策略(如Markdown格式化策略),只需创建一个MarkdownFormatterStrategy类并实现文本格式化接口,然后在环境类中使用这个新的策略类即可,而不需要修改其他已有的格式化策略类或文本编辑器的主体代码。
三、缺点
1.  客户端必须了解策略类
•  客户端需要知道所有的策略类,并且要决定使用哪一个策略类。这增加了客户端的复杂性。例如,在一个游戏中的角色移动策略选择场景中,客户端(游戏的控制逻辑部分)需要知道所有的移动策略类(如步行策略、奔跑策略、飞行策略等),并且要根据游戏的场景和角色状态来选择合适的移动策略,这就使得客户端的逻辑变得较为复杂。
2.  策略类数量可能过多
•  如果有太多的策略,会导致策略类的数量过多,这会给系统的维护带来一定的困难。比如在一个复杂的物流配送系统中,如果按照不同的配送区域、不同的货物类型、不同的配送时间等因素来划分配送策略,可能会产生大量的具体策略类,这会使得系统结构变得复杂,增加了理解和维护的难度。
四、应用场景
1.  算法选择场景
•  当一个系统有多种算法可供选择,并且在运行时需要根据不同的条件动态选择算法时,可以使用策略模式。例如,在一个图像处理软件中,有多种图像滤镜算法(如模糊滤镜、锐化滤镜、黑白滤镜等),用户可以根据需要选择不同的滤镜效果,这时就可以使用策略模式来实现不同滤镜算法的动态切换。
2.  行为变化场景
•  当一个对象的行为在运行时需要根据不同的状态或条件发生变化时,策略模式是一个很好的选择。比如在一个智能家电控制系统中,家电设备(如空调)的行为(如制冷、制热、通风等模式)会根据室内的温度、湿度等条件以及用户的设置而变化,可以使用策略模式来实现空调不同模式的行为切换。
3.  算法封装场景
•  当需要将一系列相关的算法封装起来,隐藏算法的实现细节,只暴露统一的接口给客户端时,策略模式可以发挥作用。例如,在一个金融风险评估系统中,有多种风险评估算法(如信用风险评估算法、市场风险评估算法等),这些算法的具体实现细节可以封装在不同的策略类中,而系统只需要通过统一的风险评估接口来调用这些算法,客户端不需要关心算法的具体实现。
五、实现示例(以Java语言为例)
假设我们要实现一个简单的计算器,支持加法和减法运算,使用策略模式来实现如下:
// 抽象策略类:定义计算接口
public interface CalculationStrategy {
    int doCalculation(int num1, int num2);
}

// 具体策略类:加法策略
public class AdditionStrategy implements CalculationStrategy {
    @Override
    public int doCalculation(int num1, int num2) {
        return num1 + num2;
    }
}

// 具体策略类:减法策略
public class SubtractionStrategy implements CalculationStrategy {
    @Override
    public int doCalculation(int num1, int num2) {
        return num1 - num2;
    }
}

// 环境类:计算器类
public class Calculator {
    private CalculationStrategy strategy;

    public Calculator(CalculationStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(CalculationStrategy strategy) {
        this.strategy = strategy;
    }

    public int calculate(int num1, int num2) {
        return strategy.doCalculation(num1, num2);
    }
}

// 客户端代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Calculator calculator = new Calculator(new AdditionStrategy());
        System.out.println("10 + 5 = " + calculator.calculate(10, 5));

        calculator.setStrategy(new SubtractionStrategy());
        System.out.println("10 - 5 = " + calculator.calculate(10, 5));
    }
}

在这个例子中,CalculationStrategy接口是抽象策略类,定义了计算的方法doCalculation。AdditionStrategy和SubtractionStrategy是具体策略类,分别实现了加法和减法运算。Calculator类是环境类,它持有一个CalculationStrategy类型的引用,并提供calculate方法来执行计算。客户端代码通过设置不同的策略来改变计算器的行为,实现了加法和减法运算的动态切换。


http://www.ppmy.cn/devtools/149763.html

相关文章

chrome浏览器的更新提示弹窗无法更新Chrome解决方法

使用组策略编辑器 此方法适用于 Windows 系统且系统为专业版及以上版本,家庭版系统没有组策略功能。 按下Win R键,打开 “运行” 对话框,输入gpedit.msc并回车,打开组策略编辑器。 在组策略编辑器中,依次展开 “计算机…

基于Qt/C++二维码生成器(附工程源码链接)

简介 本项目是一个基于C和Qt框架开发的二维码生成器。它通过简单的用户交互,能够快速生成二维码图像并显示在用户界面上。以下将从代码结构、实现逻辑和功能扩展等方面对该项目进行详细讲解,便于集成到其他程序中。 项目代码结构 项目的主要文件包括以…

micro-app【微前端系列教程】通信

主应用向子应用发送数据 setData 方式1 – 通过动态属性发送 vue <template><micro-appnamemy-appurlxx:datadataForChild // data只接受对象类型&#xff0c;数据变化时会重新发送/> </template><script> export default {data () {return {dataFor…

力扣经典二分题:4. 寻找两个正序数组的中位数

题目链接&#xff1a;4. 寻找两个正序数组的中位数 - 力扣&#xff08;LeetCode&#xff09; 一、题目分析 这道题目是让我们在 两个正序的数组中寻找中位数已知两个数组的大小分别是&#xff1a;int m nums1.size(),n nums2.size();中位数性质1&#xff1a;中位数左侧元素 …

uniapp uni-popup使用scroll-view滚动时,底部按钮设置position:fixed失效,部分ios设置有问题

uniapp uni-popup使用scroll-view滚动时&#xff0c;底部按钮设置position:fixed失效&#xff0c;部分ios设置有问题 尝试过多种办法&#xff0c;最后发现部分机型position:fixed失效&#xff0c;position: sticky可以用&#xff0c;但是只设置sticky的话&#xff0c;部分机型…

景芯SOC设计实战

终身辅导、一对一辅导&#xff0c;手把手教您完成SoC全流程设计&#xff0c;从入门到进阶&#xff0c;带您掌握SoC芯片架构、算法、设计、验证、DFT、后端及低功耗全流程&#xff01;直播视频不定期升级&#xff01;让您快速超越同龄人&#xff01; 景芯团队主打文档服务器实战…

58.在 Vue 3 中使用 OpenLayers 绘制点、线、圆、多边形

前言 在现代 Web 开发中&#xff0c;地图功能已经成为许多应用的重要组成部分。OpenLayers 是一个强大的开源地图库&#xff0c;支持多种地图源和地图操作。结合 Vue 3 的响应式特性&#xff0c;我们可以轻松实现地图的交互功能。本文将详细介绍如何在 Vue 3 中使用 OpenLayer…

010:传统计算机视觉之大津算法初探

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 上一节学习了利用 Canny 算法来完成一个图片的边缘检测&#xff0c;从而可以区分出图像的边缘。 本节再了解一个计算机视觉中更常见的应用&#xff0c;那就是把图片的前景和…