Java设计模式—策略模式(Strategy)

news/2024/9/19 4:54:22/ 标签: java, 设计模式, 策略模式

模式动机

  • 完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
  • 在软件开发中也常常遇到类似的情况,实现某一个功能有多个途径,此时可以使用一种设计模式来使得系统可以灵活地选择解决途径,也能够方便地增加新的解决途径。
  • 在软件系统中,有许多算法可以实现某一功能,如查找、排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难。
  • 除了提供专门的查找算法类之外,还可以在客户端程序中直接包含算法代码,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。
  • 为了解决这些问题,可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。

模式定义

策略(Strategy)模式是一种行为设计模式,它使你能在运行时改变对象的行为。它定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

模式结构

策略模式包含以下几个组成部分:

  • 策略接口(Strategy):定义了一个公共接口,所有的具体策略都要实现这个接口。
  • 具体策略(Concrete Strategy):实现了策略接口中的算法。
  • 上下文(Context):使用某个策略类,并且提供了一个接口让外部可以给它设置策略。

时序图

对于策略模式的时序图,它大致如下:

  1. 客户端决定使用哪种策略,并创建相应的具体策略对象。
  2. 客户端创建上下文对象,并将具体策略对象传递给上下文。
  3. 在某些触发条件下,上下文调用策略对象的方法来执行具体的算法。
  4. 策略对象执行其算法,并返回结果给上下文。
  5. 上下文处理结果,并将最终的结果返回给客户端。

代码分析

下面是一个简单的示例代码,展示如何使用策略模式

// 策略接口
interface PaymentStrategy {double calculateTotal(double amount);
}// 具体策略A - 不打折
class NoDiscountPayment implements PaymentStrategy {@Overridepublic double calculateTotal(double amount) {return amount;}
}// 具体策略B - 打九折
class TenPercentOffPayment implements PaymentStrategy {@Overridepublic double calculateTotal(double amount) {return amount * 0.9;}
}// 上下文
class ShoppingCart {private PaymentStrategy strategy;public ShoppingCart(PaymentStrategy strategy) {this.strategy = strategy;}public double calculateTotal(double amount) {return strategy.calculateTotal(amount);}
}

模式分析

  • 策略模式是一个比较容易理解和使用的设计模式策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
  • 策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色。
  • 策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。

实例

继续上面的购物车示例,我们可以根据用户的会员等级动态地选择不同的支付策略。例如,普通用户使用NoDiscountPayment策略,而VIP用户则使用TenPercentOffPayment策略。

优点

  • 多个类只改变其中的一个算法。
  • 客户端可以选择一个算法而不“硬编码”它。
  • 支持开闭原则:可以在不修改原有代码的情况下增加新的算法。

缺点

  • 客户端必须理解所有策略的差异,并自行决定使用哪一个策略。
  • 策略模式导致了很多小类的产生。

适用环境

  • 许多相关的类仅仅是行为有异。
  • 需要在运行时刻选择一个算法或行为。

模式应用

策略模式广泛应用于各种需要动态选择算法的场景中,比如排序算法的选择、数据库查询优化等。

模式扩展

  • 可以通过环境类状态的个数来决定是使用策略模式还是状态模式。
  • 策略模式的环境类自己选择一个具体策略类,具体策略类无须关心环境类;而状态模式的环境类由于外在因素需要放进一个具体状态中,以便通过其方法实现状态的切换,因此环境类和状态类之间存在一种双向的关联关系。
  • 使用策略模式时,客户端需要知道所选的具体策略是哪一个,而使用状态模式时,客户端无须关心具体状态,环境类的状态会根据用户的操作自动转换。
  • 如果系统中某个类的对象存在多种状态,不同状态下行为有差异,而且这些状态之间可以发生转换时使用状态模式;如果系统中某个类的某一行为存在多种实现方式,而且这些实现方式可以互换时使用策略模式

总结

  • 策略模式中定义了一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为型模式。
  • 策略模式包含三个角色:环境类在解决某个问题时可以采用多种策略,在环境类中维护一个对抽象策略类的引用实例;抽象策略类为所支持的算法声明了抽象方法,是所有策略类的父类;具体策略类实现了在抽象策略类中定义的算法。
  • 策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。
  • 策略模式主要优点在于对“开闭原则”的完美支持,在不修改原有系统的基础上可以更换算法或者增加新的算法,它很好地管理算法族,提高了代码的复用性,是一种替换继承,避免多重条件转移语句的实现方式;其缺点在于客户端必须知道所有的策略类,并理解其区别,同时在一定程度上增加了系统中类的个数,可能会存在很多策略类。
  • 策略模式适用情况包括:在一个系统里面有许多类,它们之间的区别仅在于它们的行为,使用策略模式可以动态地让一个对象在许多行为中选择一种行为;一个系统需要动态地在几种算法中选择一种;避免使用难以维护的多重条件选择语句;希望在具体策略类中封装算法和与相关的数据结构。

http://www.ppmy.cn/news/1520527.html

相关文章

【运维监控】prometheus+node exporter+grafana 监控linux机器运行情况(2)

本示例是通过prometheus的node exporter收集主机的信息,然后在grafana的dashborad进行展示。本示例使用到的组件均是最新的,下文中会有具体版本说明,linux环境是centos。本示例分为四个部分,即prometheus、grafana、node exporter…

【MySQL】如何优化 SQL UPDATE 语句以提升性能

如何优化 SQL UPDATE 语句以提升性能 在日常开发中,优化 SQL 查询是非常关键的一项任务,尤其是在处理大量数据时。本文将通过一个 UPDATE 语句的优化过程,探讨如何提升 SQL 性能。 示例场景 假设我们有以下两张表: 表 table_a…

打造一流的研发型企业--- 金发科技研发驱动力初探

2006年3月29日,国家发改委副主任欧新黔亲自为金发科技颁发了“中国改性塑料行业第一位”、“中国合成材料制造业十强”、“中国石油化工全行业百强”三块铜牌证书,金发科技终于成为名符其实的行业“老大”。公司产品销售额增长迅速, 2006年完…

开发基础软件安装地址(持续更新中)

开发基础软件安装地址(持续更新中) 如果需要新增下载工具可以在评论中留言 欢迎广大开发人员在评论区讨论关于环境安装遇到的问题 正文会持续更新。。。 java常用的jdk1.8版本安装包 链接:jdk-8u421-windows-x64.exe idea java常用的开发工具…

提交保存,要做重复请求拦截,避免出现重复保存的问题

**问题:**前端ajax提交数据的时候,当频繁点击的时候,或者两个账号以相同数据创建的时候,会出现问题。 **处理办法:**前端拦截,防止重复提交数据,在上一次请求返回结果之后才允许提交第二次&…

在 Debian 8 上安装 Nginx 的方法

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 介绍 Nginx 是一个流行的 HTTP 服务器,是 Apache2 的一个替代品。它可以用作反向代理、邮件服务器或 Web 服务器。根据 Net…

[某度信息流]SQL164,2021年11月每天新用户的次日留存率

牛客网在线编程 思路: 首先找出用户的注册日期,即date(min(in_time)) 转成date形式 建立两个辅助表,我先放代码,然后进行解释 withuser_reg as (selectuid,date(min(in_time)) as first_datefromtb_user_loggroup by1),…

抖音视频如何下载保存到相册:详细教程

随着抖音的风靡,越来越多的人沉浸在短视频的世界中,观看各种搞笑、有趣、甚至感人的视频。很多用户都希望能够将喜欢的抖音视频保存到自己的手机相册中,方便随时观看或分享给朋友。本文将详细介绍如何下载抖音视频并保存到相册的方法。 一、…

记录Jmeter 通过view result tree配置保存响应信息的方法以及命令行运行时的一个坑

大家在使用Jmeter进行调试时有没有考虑过这个问题,如何查看具体的响应信息,特别是通过命令行执行脚本的时候,如何看到具体请求的响应信息呢? 看到上面这个问题,首先想到的就是我们平时在jmeter中debug问题&#xff0c…

基于FPGA实现SD NAND FLASH的SPI协议读写

基于FPGA(现场可编程门阵列)实现SD NAND FLASH的SPI(串行外设接口)协议读写是一个涉及硬件设计与编程的复杂过程。以下将详细介绍该过程的背景、关键步骤、电路设计、SPI协议详解、FPGA实现以及代码示例等方面,内容不少…

Spark-ShuffleManager

一、上下文 《Spark-Task启动流程》中我们讲到了ShuffleMapTask中会对这个Stage的结果进行磁盘的写入,并且从SparkEnv中得到了ShuffleManager,且调用了它的getWriter方法并在这个Stage的入口处(也就是RDD的迭代器数据源处)调用了…

uniapp 自定义微信小程序 tabBar 导航栏

背景 做了一个校园招聘类小程序,使用 uniapp vue3 uview-plus pinia 构建,这个小程序要实现多角色登录,根据权限动态切换 tab 栏文字、图标。 使用pages.json中配置tabBar无法根据角色动态配置 tabBar,因此自定义tabBar&…

MySQL数据库增删查改(基础)CRUD

CRUD 即增加 (Create) 、查询 (Retrieve) 、更新 (Update) 、删除 (Delete) 四个单词的首字母缩写。 1. 新增(Create) 1.1单行数据(全列插入) 比如说:创建一张学生表,有姓名,学号。插入两个学…

新手c语言讲解及题目分享(十)——数组专项练习

C语言中的数组是一个用于存储多个同类型数据的集合。数组在内存中是连续分配的,可以通过索引访问其中的元素。以下是对C语言数组的详细讲解: 1. 数组的定义 数组的定义格式如下: type arrayName[arraySize]; - type:数组中元素…

数据结构---链表

指针和数组 数组的用途: 固定大小的存储: 数组用于存储固定大小的一组相同类型的元素。数组的大小在声明时必须指定,并且在程序运行期间不能改变。访问效率高: 数组允许通过下标进行快速访问,时间复杂度为 O(1)。内存连续性: 数组的元素在内存中是连续存…

网络安全面试经验分享:蘑菇街/网络安全

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 蘑菇街 介绍…

蓝牙协议栈API分析

蓝牙协议栈API分析是一个复杂但重要的任务,它涉及到蓝牙通信的各个方面,包括设备发现、连接建立、数据传输以及安全管理等。以下是对蓝牙协议栈API的详细分析,旨在提供一个全面的视角。 一、蓝牙协议栈概述 蓝牙协议栈是蓝牙技术实现的基础…

解决reCaptcha v2 Invisible:识别和参数

概述 reCaptcha v2 Invisible是一种旨在提供安全性而不打扰用户体验的验证码类型。与传统的验证码不同,reCaptcha v2 Invisible在检测到可疑活动时才会要求用户进行互动。本文将引导您如何使用CapSolver API识别并解决reCaptcha v2 Invisible挑战。 什么是reCaptc…

ChatGPT与R语言融合技术在生态环境数据统计分析、绘图、模型中的实践与进阶应用

自2022年GPT(Generative Pre-trained Transformer)大语言模型的发布以来,它以其卓越的自然语言处理能力和广泛的应用潜力,在学术界和工业界掀起了一场革命。在短短一年多的时间里,GPT已经在多个领域展现出其独特的价值…

计算机网络-VRRP切换与回切过程

前面我们学习了VRRP选举机制,根据VRRP优先级与IP地址确定主设备与备份设备,这里继续进行主备切换与主备回切以及VRRP抢占模式的学习。 一、VRRP主备切换 主备选举时根据优先级选择主设备,状态切换为Master状态,那当什么时候会切换…