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

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.mzph.cn/news/27774.shtml

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

相关文章

Python faker 生成测试数据

pip install Faker faker官网 基本使用 from faker import Fakerif __name__ __main__:fake Faker()print(fake.name())print(fake.user_name())print(fake.phone_number())print(fake.address()) # 输出: Jorge Campbell grobbins 769.415.0562x2019 255 Broo…

[机器学习]线性回归模型

线性回归 线性回归:根据数据,确定两种或两种以上变量间相互依赖的定量关系 函数表达式: y f ( x 1 , x 2 . . . x n ) y f(x_1,x_2...x_n) yf(x1​,x2​...xn​) ​ 回归根据变量数分为一元回归[ y f ( x ) yf(x) yf(x)]和多元回归[ y …

【深度学习Week4】MobileNet_ShuffleNet

报错:unsafe legacy renegotiation disabled 解决方案: 尝试了更换cryptography36.0.2版本,以及更换下载链接的方法,都不行,最后采用了手动下载mat文件并上传到colab的方法 高光谱图像分类数据集简介Indian Pines&…

【果树农药喷洒机器人】Part2:机器人变量喷药系统硬件选型

本专栏介绍:免费专栏,持续更新机器人实战项目,欢迎各位订阅关注。 关注我,带你了解更多关于机器人、嵌入式、人工智能等方面的优质文章! 文章目录 一、引言二、变量喷药系统总体要求2.1系统功能要求2.2系统技术要求 三…

4.1 Windows终端安全

数据参考:CISP官方 目录 安全安装保护账户安全本地安全策略安全中心系统服务安全其他安全设置软件安全获取 一、安全安装(以安装windows系统为例) 选择合适的版本 商业版本:家庭版、专业版、专业工作站版、企业版特殊版本&…

pytest-xdist分布式测试原理浅析

目录 pytest-xdist执行流程: pytest-xdist 模块结构: pytest-xdist分布式测试原理: pytest-xdist源码浅读: pytest-xdist执行流程: 解析命令行参数:pytest-xdist 会解析命令行参数,获取用户…

海外媒体发稿:软文写作方法方式?一篇好的软文理应合理规划?

不同种类的软文会有不同的方式,下面小编就来来给大家分析一下: 方法一、要选定文章的突破点: 所说突破点就是这篇文章文章软文理应以什么样的视角、什么样的见解、什么样的语言设计理念、如何文章文章的标题来写。不同种类的传播效果&#…

【hive经典指标,离线数仓指标,ADS层指标分析】最近7日内连续3日下单用户数

1.建表语句 DROP TABLE IF EXISTS ads_order_continuously_user_count; CREATE EXTERNAL TABLE ads_order_continuously_user_count (dt STRING COMMENT 统计日期,recent_days BIGINT COMMENT 最近天数,7:最近7天,order_continu…

【JMeter】 使用Synchronizing Timer设置请求集合点,实现绝对并发

目录 布局设置说明 Number of Simulated Users to Group Timeout in milliseconds 使用时需要注意的点 集合点作用域 实际运行 资料获取方法 布局设置说明 参数说明: Number of Simulated Users to Group 每次释放的线程数量。如果设置为0,等同…

MongoDB基本命令使用

成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作。 输入help可以看到基本操作命令: show dbs:显示数据库列表 show collections:显示当前数据库中的集合(类似关系数据库中的表&#xf…

vue2路由跳转和浏览器回退时弹窗的开启

文章目录 前言一、跳转到B页面的新增弹框具体流程二、返回A页面时打开详情弹框 前言 我这里有个需求是在A页面中的详情弹框中,点击按钮跳转到B页面的新增弹框中,并把A页面中的数据带过去填到B页面新增的form表单中,此时如果点击了浏览器的回…

以Java的方式将文件上传到阿里云OSS

文章目录 1. 开通对象存储服务2. 创建 AccessKey 密钥3. 通用代码实现 1. 开通对象存储服务 控制台 → 对象存储 OSS → 立即开通 Bucket列表 → 点击创建 Bucket 填写名称、地域,名称创建后不可修改,地域选择最近的,存储类型选择标准存储&…

2023-08-08 LeetCode每日一题(任意子数组和的绝对值的最大值)

2023-08-08每日一题 一、题目编号 1749. 任意子数组和的绝对值的最大值二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 nums 。一个子数组 [numsl, numsl1, …, numsr-1, numsr] 的 和的绝对值 为 abs(numsl numsl1 … numsr-1 numsr) 。 请你找出 …

Maltab之滤波带来的时延问题

直接使用lowpass, highpass, bandpass等函数时会自动对filtering带来的时延给予补偿.但是对于自己设计的filter, 利用filt来进行滤波的话就会带来时延. 可以使用函数 grpdelay(filter,N,Fs) 来查看.对于FIR filter, 造成的时延对于不同的频率相应是一致的, 那么直接移动滤波后的…

Mysql8.0变更特性

性能翻倍 账户与安全 用户的创建和授权 在MySQL之前的版本,创建用户和给创建的用户授权可以一条语句执行完成: grant all privileges on *.* to test% identified by suibowenkuangtu6;在MySQL 8中,创建用户和授权需要分开执行&#xff0c…

STM32基础入门学习笔记:核心板 电路原理与驱动编程

文章目录: 一:LED灯操作 1.LED灯的点亮和熄灭 延迟闪烁 main.c led.c led.h BitAction枚举 2.LED呼吸灯(灯的强弱交替变化) main.c delay.c 3.按键控制LED灯 key.h key.c main.c 二:FLASH读写程序(有…

LeNet卷积神经网络-笔记

LeNet卷积神经网络-笔记 手写分析LeNet网三卷积运算和两池化加两全连接层计算分析 修正上图中H,W的计算公式为下面格式 基于paddle飞桨框架构建测试代码 #输出结果为: #[validation] accuracy/loss: 0.9530/0.1516 #这里准确率为95.3% #通过运行结果可以看出&am…

Stable Diffusion - Style Editor 和 Easy Prompt Selector 提示词插件配置

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132122450 Stable Diffusion 的 Prompt 的功能,可以用文字来描述想要生成的图像,根据输入来创造出逼真的图像。Prompt 支持…

Python 面试必知必会(一):数据结构

《Python Cookbook》的作者David Beazley的课程PPT开源了,目标用户是希望从编写基础脚本过渡到编写更复杂程序的高级 Python 程序员,课程主题侧重于流行库和框架中使用的编程技术,主要目的是更好地理解 Python 语言本身,以便阅读他…

【深度学习】采用自动编码器生成新图像

一、说明 你知道什么会很酷吗?如果我们不需要所有这些标记的数据来训练 我们的模型。我的意思是标记和分类数据需要太多的工作。 不幸的是,大多数现有模型从支持向量机到卷积神经网,没有它们,卷积神经网络就无法训练。无监督学习不…