策略模式——算法的封装与切换

1、简介

1.1、概述

在软件开发中,常常会遇到这种情况,实现某一个功能有多条途径。每一条途径对应一种算法,此时可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。为了适应算法灵活性而产生的设计模式——策略模式。

在策略模式中,可以定义一些独立的类来封装不同的算法,每个类封装一种具体的算法。在这里,每个封装算法的类都可以称之为一种策略(Strategy)。为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。

策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开。将算法的定义放在专门的策略类中,每个策略类封装了一种实现算法。使用算法的环境类针对抽象策略类进行编程,符合依赖倒转原则。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。

1.2、定义

策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。

2、解析

2.1、UML类图

策略模式结构并不复杂,但需要理解其中环境类Context的作用,其结构如下图所示:
在这里插入图片描述
可以看出,在策略模式结构图中包含以下3个角色:

  1. Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
  2. Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类。它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
  3. ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法。在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。

2.2、代码示例

策略模式是一个比较容易理解和使用的设计模式。策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列具体策略类里面,作为抽象策略类的子类。在策略模式中,对环境类和抽象策略类的理解非常重要,环境类是需要使用算法的类。在一个系统中可以存在多个环境类,它们可能需要重用一些相同的算法。

在使用策略模式时,需要将算法从Context类中提取出来。首先应该创建一个抽象策略类,其典型代码如下:

/*** @Description: 抽象策略* @Author: yangyongbing* @CreateTime: 2023/08/03  * @Version: 1.0*/
abstract class AbstractStrategy {// 声明抽象算法public abstract void algorithm();
}

然后再将封装每一种具体算法的类作为该抽象策略类的子类,代码如下:

/*** @Description: 具体算法的类* @Author: yangyongbing* @CreateTime: 2023/08/03  * @Version: 1.0*/
public class ConcreteStrategyA extends AbstractStrategy{// 算法的具体实现@Overridepublic void algorithm() {// 算法 A}
}

其他具体策略类与之类似。对于Context类而言,在它与抽象策略类之间建立一个关联关系,其典型代码如下:

public class Context {// 持有一个对抽象策略类的引用private AbstractStrategy strategy;public void setStrategy(AbstractStrategy strategy) {this.strategy = strategy;}// 调用策略类中的算法public void algorithm(){strategy.algorithm();}
}

在Context类中定义一个AbstractStrategy类型的对象strategy。通过注入的方式在客户端传入一个具体策略对象,客户端代码片段如下:

Context  context = new Context();
AbstractStrategy strategy;
// 可在运行时指定类型
context.setStrategy(strategy);
context.algorithm();

在客户端代码中只需注入一个具体策略对象。可以将具体策略类类名存储在配置文件中,通过反射来动态创建具体策略对象,从而使得用户可以灵活地更换具体策略类,增加新的具体策略类也很方便。策略模式提供了一种可插入式(Pluggable)算法的实现方案。

3、策略模式总结

策略模式用于算法的自由切换和扩展,它是应用较为广泛的设计模式之一。策略模式对应于解决某一问题的一个算法族,允许用户从该算法族中任选一个算法来解决某一问题,同时可以方便地更换算法或者增加新的算法。只要涉及算法的封装、复用和切换都可以考虑使用策略模式。

3.1、主要优点

  1. 策略模式提供了对开闭原则的完美支持。用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  2. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到抽象策略类中,从而避免重复代码。
  3. 策略模式提供了一种可以替换继承关系的办法。如果不使用策略模式,那么使用算法的环境类就可能会有一些子类,每一个子类提供一种不同的算法。但是,这样一来算法的使用就和算法本身混在一起,不符合单一职责原则。决定使用哪一种算法的逻辑和该算法本身混合在一起,从而不可能再独立演化;而且使用继承无法实现算法或行为在程序运行时的动态切换。
  4. 使用策略模式可以避免多重条件选择语句。多重条件选择语句不易维护,它把采取哪一种算法或行为的逻辑与算法或行为本身的实现逻辑混合在一起,将它们全部硬编码(Hard Coding)在一个庞大的多重条件选择语句中,比直接继承环境类的办法还要原始和落后。
  5. 策略模式提供了一种算法的复用机制。由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。

3.2、主要缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
  2. 策略模式将造成系统产生很多具体策略类。任何细小的变化都将导致系统要增加一个新的具体策略类。
  3. 无法同时在客户端使用多个策略类。也就是说,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。

3.3、适用场景

  1. 一个系统需要动态地在几种算法中选择一种。可以将这些算法封装到一个个的具体算法类中,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均具有统一的接口。根据里氏代换原则和面向对象的多态性,客户端可以选择使用任何一个具体算法类,并只需要维持一个数据类型是抽象算法类的对象。
  2. 一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句。
  3. 不希望客户端知道复杂的、与算法相关的数据结构。在具体策略类中封装算法与相关的数据结构,可以提高算法的保密性与安全性。

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

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

相关文章

【工程优化问题】基于多种智能优化算法的压力容器设计问题研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

【C# 基础精讲】循环语句:for、while、do-while

循环语句是C#编程中用于重复执行一段代码块的关键结构。C#支持for、while和do-while三种常见的循环语句,它们允许根据条件来控制代码块的重复执行。在本文中,我们将详细介绍这三种循环语句的语法和使用方法。 for循环 for循环是一种常见的循环结构&…

进程通信常见方式

目录 通信通信概述 通信的主要方式 进程同步机制--低级进程通信 高级通信工具 共享存储器系统(Shared-Memory System) 管道(pipe)通信系统 客户机-服务器系统(Client-Server system)---套接字(Socket) 客户机-服务器系统(Client-Serv…

微信小程序开发【从0到1~入门篇】2023.08

一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下: 文件必须作用app.js是小程序逻辑app.json是小程序公告配置app.wxss否小程序公告样式表 3. 小程序项目结构 一个小程序页面由四个文件组成,分别是: 文…

JUC并发编程(JUC核心类、TimeUnit类、原子操作类、CASAQS)附带相关面试题

目录 1.JUC并发编程的核心类 2.TimeUnit(时间单元) 3.原子操作类 4.CAS 、AQS机制 1.JUC并发编程的核心类 虽然java中的多线程有效的提升了程序的效率,但是也引发了一系列可能发生的问题,比如死锁,公平性、资源管理…

Redis—持久化

这里写目录标题 AOF三种写回策略写回策略的优缺点AOF 重写机制AOF后台重写AOF优缺点使用命令 RDBRDB 持久化的工作原理执行快照时,数据能被修改吗RDB 持久化的优点RDB 持久化的缺点 混合持久化大key对持久化的影响 AOF 保存写操作命令到日志的持久化方式&#xff0…

MyBatis核心 - SqlSession如何通过Mapper接口生成Mapper对象

书接上文 MyBatis – 执行流程 我们通过SqlSession获取到了UserMapper对象,代码如下: // 获取SqlSession对象 SqlSession sqlSession sqlSessionFactory.openSession();// 执行查询操作 try {// 获取映射器接口UserMapper userMapper sqlSession.get…

什么CRM客户管理系统好用?公司规模不大,有推荐吗?

CRM客户管理系统是什么? 一句话来概括:CRM是客户关系管理的缩写,指企业通过建立客户档案、跟进客户需求、提供优质服务来维系客户关系的一种管理模式。通常我们认知中的CRM管理系统软件,往往作用于企业的三个流程: 1…

机器学习笔记之优化算法(十)梯度下降法铺垫:总体介绍

机器学习笔记之优化算法——梯度下降法铺垫:总体介绍 引言回顾:线搜索方法线搜索方法的方向 P k \mathcal P_k Pk​线搜索方法的步长 α k \alpha_k αk​ 梯度下降方法整体介绍 引言 从本节开始,将介绍梯度下降法 ( Gradient Descent,GD ) …

学习总结(TAT)

好久都没交总结了,今天把之前的思路和错误整理了一下: 在服务器和客户端两侧,不可以同时先初始化获取输入流,否则会造成堵塞,同时为这位作者大大打call: (3条消息) 关于Java Socket和创建输入输出流的几点…

实战项目ssm权限系统 3-自定义注解+AOP拦截器记录登录日志

一 登录日志以及操作操作日志的操作 1.1 登录日志配置收集 1.1.1 编写log入库的service层接口 1.接口:在spring-security模块中 2.实现类:在service-system模块中 3.dao层:在service-system模块中 1.1.2 过滤器添加log记录 在过滤器中&…

01_什么是ansible、基本架构、ansible工作机制、Ansible安装、配置主机清单、设置SSH无密码登录等

1.什么是ansible 1.1.基本介绍 1.2.基本架构 1.3.基本特征 1.4.优点 1.5.ansible工作机制 2.Ansible安装 2.1.机器准备 2.2.安装ansible 2.2.1.安装epel源 2.2.2.安装ansible 2.2.3.查看ansible版本 2.2.4.树状结构展示文件夹 2.2.4.1.其中ansible.cfg的内容如下 2.2.4.2.host的…

ts中interface自定义结构约束和对类的约束

一、interface自定义结构约束对后端接口返回数据 // interface自定义结构 一般用于较复杂的结构数据类型限制 如后端返回的接口数据// 首字母大写;用分割号隔开 interface Iobj{a:number;b:string } let obj:Iobj {a:1,b:2 }// 复杂类型 模拟后端返回的接口数据 interface Il…

管理类联考——逻辑——论证逻辑——汇总篇——真题和典例——削弱

削弱 199-2014-10-41——割裂关系 卫计委的报告表明,这些年来医疗保健费的确是增加了。可见,我们每个人享受到的医疗条件大大改善了。 以下哪项对上述结论提出最严重的质疑? A.医疗保健费的绝大部分用在了对高危病人的高技术强化护理上。 B.在不增加费…

Spring事务管理

目录 1.什么是事务 事务的四大特性(ACID) 2.Spring中的事务 2.1PlatformTransactionManager 2.2TransactionDefinition 2.3TransactionStatus 3.编程式事务 4.声明式事务(Transactional) 5. 事务属性 5.1 隔离性(isolat…

Linux-GPIO 配置pull up、pull down、no pull

author daisy.skye的博客_CSDN博客-Qt,嵌入式,Linux领域博主 https://blog.csdn.net/qq_40715266?typeblog 系列基于RK3568的Linux驱动开发——GPIO知识点(一)_daisy.skye的博客-CSDN博客基于RK3568的Linux驱动开发—— GPIO知识点(二&#…

【VisualGLM】大模型之 VisualGLM 部署

目录 1. VisualGLM 效果展示 2. VisualGLM 介绍 3. VisualGLM 部署 1. VisualGLM 效果展示 VisualGLM 问答 原始图片 2. VisualGLM 介绍 VisualGLM 主要做的是通过图像生成文字,而 Stable Diffusion 是通过文字生成图像。 一种方法是将图像当作一种特殊的语言进…

C语言刷题------(2)

C语言刷题——————(2) 刷题网站:题库 - 蓝桥云课 (lanqiao.cn) First Question:时间显示 题目描述 小蓝要和朋友合作开发一个时间显示的网站。 在服务器上,朋友已经获取了当前的时间,用一个整数表…

Nginx与docker配置安装

目录: Nginx的安装配置: 1、安装依赖包: 2、下载Nginx安装包: 3、解压Nginx压缩包: 4、配置Nginx编译环境: 5、编译并安装Nginx: 6、安装完Nginx后,可以切换到Nginx的安装目录…

python版《羊了个羊》游戏开发第一天

Python小型项目实战教学课《羊了个羊》 一、项目开发大纲(初级) 版本1.0:基本开发 课次 内容 技术 第一天 基本游戏地图数据 面向过程 第二天 鼠标点击和移动 面向对象 第三天 消除 设计模式:单例模式 第四天 完整…