设计模式-策略模式(Strategy)

设计模式-策略模式(Strategy)

    • 一、策略模式概述
      • 1.1 什么是策略模式
      • 1.2 简单实现策略模式
      • 1.3 使用策略模式的注意事项
    • 二、策略模式的用途
    • 三、策略模式实现方式
      • 3.1 简单策略模式
      • 3.2 组合策略模式
      • 3.3 动态策略模式

一、策略模式概述

1.1 什么是策略模式

策略模式是一种行为型设计模式,它定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换或独立于使用它的客户而变化。这种类型的设计模式属于行为型模式。当在处理一项业务时,如果有多种处理方式,并且需要再运行时决定使用哪一种具体实现,就会使用策略模式。

策略模式的主要组成部分包括抽象策略(Strategy)类、具体策略(Concrete Strategy)类和环境(Context)类。抽象策略类是策略接口,定义了所有支持的算法;具体策略类是实现了抽象策略接口的类,表示每种具体的算法;环境类则负责接受客户的请求,并确定使用哪种具体策略来处理该请求。

策略模式的优点在于降低系统的耦合度,提高系统的灵活性和扩展性。缺点在于增加了系统的复杂性和理解难度。

1.2 简单实现策略模式

首先,定义一个策略接口:

public interface Strategy {void execute();
}

然后,创建具体策略类实现该接口:

public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略B");}
}

接下来,创建一个上下文类,用于管理策略:

public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
}

最后,在主函数中测试策略模式:

public class Main {public static void main(String[] args) {Context context = new Context(new ConcreteStrategyA()); // 使用策略A初始化上下文对象context.executeStrategy(); // 输出:执行策略Acontext.setStrategy(new ConcreteStrategyB()); // 更改上下文对象的策略为策略Bcontext.executeStrategy(); // 输出:执行策略B}
}

在这个示例中,我们定义了一个策略接口Strategy,并创建了两个具体策略类ConcreteStrategyA和ConcreteStrategyB。Context类负责管理当前策略,并在需要时更改策略。通过调用context.executeStrategy()方法,我们可以执行当前策略

1.3 使用策略模式的注意事项

  • 1、当一个系统的策略多于四个时,需要考虑使用混合模式,解决策略类膨胀的问题。
  • 2、策略模式包含四个核心角色:环境(Context)、抽象策略(Abstract Strategy)、具体策略(Concrete Strategy)和客户端。客户端代码不需要知道具体的算法细节,而是通过调用环境类来使用所选择的策略。
  • 3、策略模式的优点在于降低系统的耦合度,提高系统的灵活性和扩展性,但增加了系统的复杂性和理解难度。如果使用得当,可以避免使用多重条件语句,如if…else语句、switch…case语句。
  • 4、由于所有策略类都需要对外暴露,可能会增加系统的复杂度和维护难度。在设计时需要充分考虑这一点。

二、策略模式的用途

策略模式是一种行为型设计模式,它主要用于解决算法选择问题。其主要特点在于能够将一系列算法封装起来,并让它们可以互相替换或独立于使用它的客户而变化。

策略模式的应用场景主要包括以下两种:

  • 1、行为切换:当系统的许多类的区别仅在于其行为不同时,可以使用策略模式将这些不同的行为动态地让用户对象在其间进行选择。例如,对于同一个计算问题,用户可以选择使用加法策略将两个数相加,也可以选择使用乘法策略将两个数相乘。在这种情况下,每种策略都封装了一套独立的业务逻辑和计算方式。
  • 2、算法选择:在需要动态地在几种算法中选择一种的场景下,也可以使用策略模式。比如在处理大量数据时,我们可能需要根据具体情况选择最合适的排序算法,如冒泡排序、快速排序或归并排序等。这时,每种排序算法都可以被视为一种策略。
    策略模式的优点主要在于降低了系统的耦合度,提高了系统的灵活性和扩展性。通过使用策略模式,我们可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。此外,策略模式提供了对开闭原则的支持,即在不修改原有系统的基础上选择不同的行为,也可以额外扩展其它行为。

三、策略模式实现方式

3.1 简单策略模式

首先,我们定义一个策略接口:

public interface Strategy {void execute();
}

然后,我们创建两个具体的策略类,分别实现这个接口:

public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略 A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略 B");}
}

接下来,我们创建一个上下文类,用于根据需要选择不同的策略:

public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
}

最后,我们在客户端代码中使用这些类:

public class Client {public static void main(String[] args) {// 使用策略 AContext context = new Context(new ConcreteStrategyA());context.executeStrategy();// 切换到策略 Bcontext.setStrategy(new ConcreteStrategyB());context.executeStrategy();}
}

运行客户端代码,将输出:

执行策略 A
执行策略 B

3.2 组合策略模式

首先,创建一个抽象组件接口(IStrategy):

public interface IStrategy {void execute();
}

然后,创建具体组件类(ConcreteComponent),它实现了抽象组件接口:

public class ConcreteComponent implements IStrategy {@Overridepublic void execute() {System.out.println("执行具体组件的操作");}
}

接下来,创建上下文类(Context),它也实现了抽象组件接口。在上下文类中,我们可以添加一个成员变量来存储具体的策略对象,并提供一个方法来设置具体的策略对象:

public class Context implements IStrategy {private IStrategy strategy;public void setStrategy(IStrategy strategy) {this.strategy = strategy;}@Overridepublic void execute() {if (strategy != null) {strategy.execute();} else {System.out.println("没有设置策略");}}
}

最后,创建具体的策略类(ConcreteStrategyA 和 ConcreteStrategyB),它们也实现了抽象组件接口:

public class ConcreteStrategyA implements IStrategy {@Overridepublic void execute() {System.out.println("执行策略A的操作");}
}public class ConcreteStrategyB implements IStrategy {@Overridepublic void execute() {System.out.println("执行策略B的操作");}
}

在客户端代码中,我们可以创建一个上下文对象,然后根据需要设置不同的策略对象,并执行相应的操作:

public class Client {public static void main(String[] args) {Context context = new Context();context.setStrategy(new ConcreteStrategyA());context.execute(); // 输出:执行策略A的操作context.setStrategy(new ConcreteStrategyB());context.execute(); // 输出:执行策略B的操作}
}

这个示例展示了如何在运行时动态地改变对象的行为。通过使用组合策略模式,我们可以轻松地为对象添加新的策略,而无需修改其现有代码。

3.3 动态策略模式

首先,创建一个策略接口:

public interface Strategy {void execute();
}

然后,创建两个实现策略接口的具体策略类:

public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略B");}
}

接下来,创建一个上下文类,用于根据条件选择并执行相应的策略:

public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
}

最后,在客户端代码中,可以根据条件创建不同的策略对象,并将其设置到上下文对象中,然后执行策略:

public class Client {public static void main(String[] args) {// 根据条件选择策略AStrategy strategyA = new ConcreteStrategyA();Context context = new Context(strategyA);context.executeStrategy(); // 输出:执行策略A// 根据条件选择策略BStrategy strategyB = new ConcreteStrategyB();context.setStrategy(strategyB);context.executeStrategy(); // 输出:执行策略B}
}

通过这种方式,可以在运行时根据条件动态地改变策略对象,从而实现动态策略模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/142724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

225.用队列实现栈(LeetCode)

思路 思路:用两个队列实现栈后进先出的特性 ,两个队列为空时,先将数据都导向其中一个队列。 当要模拟出栈时,将前面的元素都导入另一个空队列,再将最后一个元素移出队列 实现 实现: 因为C语言没有库可以…

std::map使用自定义的数据结构当做key

一、std::map是按照键的顺序进行排序的&#xff0c;因此需要定义结构类型的比较运算符。通常情况下&#xff0c;你可以通过重载结构类型的小于运算符<来定义比较逻辑。 #include <map>class CKey { public:CKey(int a) { m_a a; }~CKey() default;//也可以在外部(二…

【Linux篇】冯 诺依曼计算机结构体系

详解冯 诺伊曼体系 CPU : 运算器 && 控制器输入设备 : 话筒&#xff0c;摄像头&#xff0c;键盘&#xff0c;鼠标&#xff0c;磁盘&#xff0c;网卡等输出设备 : 显卡&#xff0c;声卡&#xff0c;网卡&#xff0c;磁盘&#xff0c;显示器&#xff0c;打印机等存储器 :…

中睿天下Coremail | 2023年Q3企业邮箱安全态势观察报告

10月25日&#xff0c;北京中睿天下信息技术有限公司联合Coremail邮件安全发布《2023年第三季度企业邮箱安全性研究报告》。2023年第三季度企业邮箱安全呈现出何种态势&#xff1f;作为邮箱管理员&#xff0c;我们又该如何做好防护&#xff1f; 以下为精华版阅读&#xff0c;如需…

景联文科技:驾驭数据浪潮,赋能AI产业——全球领先的数据标注解决方案供应商

根据IDC相关数据统计&#xff0c;全球数据量正在经历爆炸式增长&#xff0c;预计将从2016年的16.1ZB猛增至2025年的163ZB&#xff0c;其中大部分是非结构化数据&#xff0c;被直接利用&#xff0c;必须通过数据标注转化为AI可识别的格式&#xff0c;才能最大限度地发挥其应用价…

arcgis--浮点型栅格数据转整型

利用【Spatial Analyst工具】-【数学】-【转为整型】工具&#xff0c;将浮点型数据转为整型。如下&#xff1a; 【转为整型】对话框参数设计如下&#xff1a; 转换结果如下&#xff1a;

C_8练习题

一、单项选择题(本大题共20小题,每小题2分,共40分。在每小题给出的四个备选项中,选出一个正确的答案,并将所选项前的字母填写在答题纸的相应位置上。) 编写C语言程序一般需经过的几个步骤依次是()。 A.编辑、调试、编译、连接 B.编辑、编译、连接、运行 C.编译、调试、编辑、连…

阿里云全球故障凸显“云集中”风险

阿里云12日发生的全球性故障再次将“云集中风险”推上风口浪尖。这一公有云史上罕见的事件不仅影响了数以万计的企业和服务&#xff0c;也引发了对云服务集中化趋势的深刻反思。 2023年11月12日17:44(GMT8)开始&#xff0c;阿里云基础设施发生严重故障&#xff0c;导致阿里巴巴…

【多线程 - 07、中断线程 interrupt】

中断线程 Thread类中interrupt()、interrupted()和isInterrupted()方法 interrupt()方法 其作用是中断此线程&#xff08;此线程不一定是当前线程&#xff0c;而是指调用该方法的Thread实例所代表的线程&#xff09;&#xff0c;但实际上只是给线程设置一个中断标志&#xff0c…

详解 KEIL C51 软件的使用·设置工程·编绎与连接程序

详解 KEIL C51 软件的使用建立工程-CSDN博客 2. 设置工程 (1)在图 2-15 的画面中点击 会弹出如图 2-16 的对话框.其中有 10 个选择页.选择“Target” 项,也就是图 2-16 的画面. 图 2-16 在图 2-16 中,箭头所指的是晶振的频率值,默认是所选单片机最高的可用频率值.该设置值与单…

uniapp运行到安卓模拟器一直在“同步手机端程序文件完成“界面解决办法

如果你是用的模拟器是android studio创建的模拟器&#xff0c;那么你需要新创建一个android11 x86架构的模拟器&#xff1a; 创建完成后&#xff0c;启动模拟器&#xff1a; 然后在hbuilder中重新运行到这个模拟器就可以了&#xff1a; 运行结果&#xff1a; 如果你是用安…

代码随想录Day45 动态规划13 LeetCode T1143最长公共子序列 T1135 不相交的线 T53最大子数组和

LeetCode T1143 最长公共子序列 题目链接:1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 题目思路: 动规五部曲分析 1.确定dp数组的含义 这里dp数组的含义是结尾分别为i-1,j-1的text1和text2的最长公共子序列长度 至于为什么是i-1,j-1我之前已经说过了,这里再…

网络运维Day16

文章目录 Docker简介什么是容器命名空间&#xff1a; Docker 的优缺点 Docker安装Docker镜像管理什么是镜像镜像管理 Docker容器管理运行容器容器启动、停止、重启拷贝文件进入容器容器与应用 DockerfileDockerfile 语法案例 总结 Docker简介 什么是容器 容器是用来装东西的&a…

CSS特效010:文字颜色渐变的流光效果

查看专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS相关的库、…

爱上C语言:整型和浮点型在内存中的存储(进制转换,原码,反码,补码以及大小端)

&#x1f680; 作者&#xff1a;阿辉不一般 &#x1f680; 你说呢&#xff1a;生活本来沉闷&#xff0c;但跑起来就有风 &#x1f680; 专栏&#xff1a;爱上C语言 &#x1f680;作图工具&#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话&#xff0c;还请…

揭秘Vue中的nextTick:异步更新队列背后的技术原理大揭秘!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、N…

go-bindata - embed结合嵌入静态文件打包可执行二进制文件

## embed 嵌入静态文件到可执行二进制文件 # 安装go-bindata go get -u github.com/jteeuwen/go-bindata/... # 打包静态文件 go-bindata web/... 执行次命令之后会在项目目录下生成bindata.go文件,示例命令中模板文件都在项目的web目录下 # 使用embed注册模板示例文档 http…

Git 修改历史 commit message

一. 修改最新的 commit log 修改最近一次commit message&#xff0c; 直接使用命令 git commit --amend 就可以完成修改二. 修改历史 commit log 查看日志(按 q 退出) git log --oneline # 查看5步的log。 git log --oneline -5选择要修改的commit 信息 # 要修改的 commit log…

邦芒攻略:新手求职面试需要准备的材料

新手求职面试需要准备的材料&#xff0c;求职材料是求职者写给用人单位的信&#xff0c;目的是让对方了解自己&#xff0c;准备好充足的资料和自信的心态会让面试通过的几率大大增强&#xff0c;那么应聘者需要准备的材料呢&#xff0c;来看看吧。 ​ ​1、求职信。也是求职者…