设计模式 行为型 策略模式(Strategy Pattern)与 常见技术框架应用 解析

news2025/1/9 21:57:24

在这里插入图片描述
策略模式(Strategy Pattern)核心思想是将算法的实现从使用该算法的类中分离出来,作为独立的对象,通过接口来定义算法家族,这样就可以很容易地改变或扩展算法。通过这种方式,可以避免在客户端代码中使用大量的条件语句来选择不同的行为方式,从而提高了代码的灵活性和可维护性。

一、核心思想

策略模式(Strategy Pattern)是一种行为设计模式,它允许对象在运行时动态地选择算法或行为。其核心思想是“定义一系列算法,将每个算法都封装起来,并且使它们之间可以互换”,从而增加系统的灵活性和可扩展性。

二、定义与结构

  • 定义:策略模式是一种行为设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。
  • 结构
    • 环境(Context)类:它是使用策略的类,维护一个对策略对象的引用。在游戏角色的例子中,角色类就是环境类,它会有一个属性来保存攻击策略。
    • 抽象策略(Strategy)类:定义了一个公共接口,用于所有具体策略类实现。比如定义一个attack()接口,所有不同的攻击策略都要实现这个接口。
    • 具体策略(Concrete Strategy)类:实现了抽象策略类中的接口,提供具体的算法实现。例如战士的近身攻击策略类和法师的远程攻击策略类。

三、角色

  • 环境(Context)角色
    • 持有一个具体策略的对象,可以动态地改变持有的策略对象,并在运行时调用具体策略的方法。
  • 抽象策略(Strategy)角色
    • 定义了一个公共接口,所有的具体策略类都必须实现这个接口。
  • 具体策略(Concrete Strategy)角色
    • 实现了抽象策略接口,封装了具体的算法或行为。

四、实现步骤及代码示例

  1. 步骤一:定义抽象策略类
// 抽象策略接口
public interface MemberStrategy {
    double calcPrice(double booksPrice);
}
  1. 步骤二:定义具体策略类
// 具体策略类:初级会员折扣
public class PrimaryMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("对于初级会员没有折扣");
        return booksPrice;
    }
}

// 具体策略类:中级会员折扣
public class IntermediateMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("对于中级会员的折扣为10%");
        return booksPrice * 0.9;
    }
}

// 具体策略类:高级会员折扣
public class AdvancedMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("对于高级会员的折扣为20%");
        return booksPrice * 0.8;
    }
}
  1. 步骤三:定义环境类
// 环境类
public class Price {
    private MemberStrategy strategy;

    public Price(MemberStrategy strategy) {
        this.strategy = strategy;
    }

    public double quote(double booksPrice) {
        return this.strategy.calcPrice(booksPrice);
    }
}
  1. 步骤四:使用策略模式
// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 选择并创建需要使用的策略对象
        MemberStrategy strategy = new AdvancedMemberStrategy();
        // 创建环境对象
        Price price = new Price(strategy);
        // 计算价格
        double quote = price.quote(300);
        System.out.println("图书的最终价格为: " + quote);
    }
}

五、常见技术框架应用

1、排序算法

在Python中,sorted()函数就使用了策略模式的思想。sorted()函数可以接受一个key参数,这个key参数实际上就是一个策略。

# 定义一个简单的列表
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
# 按照元素大小排序(默认策略)
sorted_list_default = sorted(my_list)
print(sorted_list_default)
# 定义一个按照元素绝对值大小排序的策略
def absolute_value_key(item):
    return abs(item)
sorted_list_absolute = sorted(my_list, key = absolute_value_key)
print(sorted_list_absolute)

2、支付方式

以下是一个使用策略模式在前端框架中实现不同支付方式的示例代码:

// 定义支付策略接口
interface PaymentStrategy {
    pay(amount: number): void;
}

// 实现具体的支付策略类(如支付宝支付、微信支付等)
class AlipayStrategy implements PaymentStrategy {
    pay(amount: number) {
        console.log(`使用支付宝支付了:${amount}`);
    }
}

class WeChatPayStrategy implements PaymentStrategy {
    pay(amount: number) {
        console.log(`使用微信支付了:${amount}`);
    }
}

// 定义上下文类,用于持有支付策略的引用并在需要时调用具体的支付策略
class PaymentContext {
    private paymentStrategy: PaymentStrategy;

    setPaymentStrategy(strategy: PaymentStrategy) {
        this.paymentStrategy = strategy;
    }

    executePayment(amount: number) {
        this.paymentStrategy.pay(amount);
    }
}

// 使用示例
const context = new PaymentContext();
context.setPaymentStrategy(new AlipayStrategy());
context.executePayment(100);  // 输出: 使用支付宝支付了:100元

context.setPaymentStrategy(new WeChatPayStrategy());
context.executePayment(200);  // 输出: 使用微信支付了:200元

在这个示例中,我们定义了一个支付策略接口PaymentStrategy,并实现了两个具体的支付策略类AlipayStrategyWeChatPayStrategy。然后,我们定义了一个上下文类PaymentContext,它持有一个支付策略的引用,并提供了设置支付策略和执行支付的方法。在客户端代码中,我们可以通过设置不同的支付策略来动态地选择支付方式。

六、应用场景

多个类只在行为上有区别,而算法和行为需要在运行时可互换的场景。
需要避免使用多重条件转移语句的场景。
当需要使用不同的变体算法时。算法族被定义成一系列的算法类,而每类实现一种算法的场景。

策略模式广泛应用于各种需要算法替换和行为切换的场景中,如:

  1. 促销活动:满减促销、返现促销、打折促销等。
  2. 排序算法:快速排序、归并排序、堆排序等。
  3. 数据搜索:二分搜索、线性搜索等。
  4. 支付方式:信用卡支付、第三方支付、货到付款等。
  5. 数据压缩:无损压缩(如zip、gzip)和有损压缩(如jpeg、mp3)。
  6. 游戏AI:根据不同关卡和难度,切换敌人的行为策略或玩家的辅助策略。

七、优缺点

优点

  1. 可扩展性强:可以很容易地添加新的策略,只要实现抽象策略类的接口即可。例如在游戏中添加新的角色攻击方式,只需要创建一个新的具体策略类。
  2. 代码复用性高:具体策略类可以在多个环境类中复用。例如不同的游戏场景可能都用到战士的攻击策略。
  3. 符合开闭原则:对扩展开放,对修改关闭。当需要添加新策略时,不需要修改环境类和其他已有的策略类。

缺点

  1. 策略类数量增多:如果有很多策略,会导致策略类的数量增加,使得代码结构变得复杂,需要管理更多的类。
  2. 客户端必须了解策略差异:客户端(环境类)需要知道不同策略之间的区别,才能正确地选择和使用策略。例如在游戏角色选择攻击策略时,需要知道每个策略对应的攻击方式。

在这里插入图片描述

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

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

相关文章

Unity 热更新基础知识

文章目录 1.一些名词2.三种编译方式3.Unity 两种脚本后端3.1 Mono3.2 IL2CPP3.3 对比 1.一些名词 IL(Intermediate Language):中间语言(类似于汇编代码)CIL(Common Intermediate Language)&…

C++感受15-Hello STL 泛型启蒙

生鱼片和STL的关系,你听过吗?泛型编程和面向对象编程,它们打架吗?行为泛型和数据泛型,各自的目的是? 0 楔 俄罗斯生鱼片,号称俄罗斯版的中国烤鸭,闻名于世。其鱼肉,源于…

LabVIEW轴承性能测试系统

本文介绍了基于LabVIEW的高效轴承性能测试系统的设计与开发。系统通过双端驱动技术实现高精度同步控制,针对轴承性能进行全面的测试与分析,以提高轴承的可靠性和寿命。 项目背景 随着工业自动化程度的提高,对轴承的性能要求越来越高。传统的…

(k8s)Flannel Error问题解决!

1.问题描述 书接上回,我们在解决kubectl不断重启的时候引入了Flannel 网络插件,但是一上来就报错, 2.问题解决 自己的思路:照例开始检查 1.先检查一下目前Flannel的pod kubectl get pods --all-namespaces 2.检查 Flannel的po…

CatLog的使用

一 CatLog的简介 1.1 作用 CAT(Central Application Tracking) 是基于 Java 开发的实时应用监控平台,为美团点评提供了全面的实时监控告警服务。 1.2 组成部分 1.2.1 Transaction 1.Transaction 适合记录跨越系统边界的程序访问行为&a…

深入Android架构(从线程到AIDL)_18 SurfaceView的UI多线程02

目录 2、 使用SurfaceView画2D图 范例一 设计GameLoop(把小线程移出来) 范例二 2、 使用SurfaceView画2D图 范例一 以SurfaceView绘出Bitmap图像设计SpriteView类别来实作SurfaceHolder.Callback接口首先来看个简单的程序,显示出一个Bitmap图像。这个图像就构…

【FlutterDart】 拖动边界线改变列宽类似 vscode 那种拖动改变编辑框窗口大小(11 /100)

【Flutter&Dart】 拖动改变 widget 的窗口尺寸大小GestureDetector~简单实现(10 /100) 【Flutter&Dart】 拖动边界线改变列宽并且有边界高亮和鼠标效果(12 /100) 上效果: 这个在知乎里找到的效果&…

tk GMV MAX素材范围投放指南

Product GMy Max素材范围说明 Product GMy Max能自动获取带有相关商品锚点链接(无论是单个锚点还是多个锚点)的视频,并将其用于推广特定商品的广告素材,前提是这些视频已经获得广告授权。然而,请注意,多个…

物联网无线芯片模组方案,设备智能化交互升级,ESP32-C3控制应用

无线交互技术的核心在于实现设备之间的无缝连接和数据传输。在智能家居系统中,各种智能设备如智能灯泡、智能插座、智能门锁等,都通过无线网络相互连接,形成一个互联互通的生态。 用户可以通过语音助手、手机APP或其他智能终端,远…

ubuntu为Docker配置代理

终端代理 我们平常在ubuntu终端中使用curl或git命令时,往往会很慢。 所以,首先需要给ubuntu终端环境添加代理。 查看自身那个软件的端口号,我这里是7890。 sudo gedit ~/.bashrcexport http_proxyhttp://localhost:7890 export https_pr…

【VUE 指令学习笔记】

v-bind :单向绑定解析表达式,可简写为:xxx v-model :双向数据绑定。 v-for:遍历数组/对象/字符串 v-on:绑定事件监听,可简写为。 v-if:条件渲染(动态控制节点是否存存在) v-else:条件渲染(动态控制节点是否存存在) v-show:条件渲染…

用OpenCV实现UVC视频分屏

分屏 OpencvUVC代码验证后话 用OpenCV实现UVC摄像头的视频分屏。 Opencv opencv里有很多视频图像的处理功能。 UVC Usb 视频类,免驱动的。视频流格式有MJPG和YUY2。MJPG是RGB三色通道的。要对三通道进行分屏显示。 代码 import cv2 import numpy as np video …

123.【C语言】数据结构之快速排序挖坑法和前后指针法

目录 1.挖坑法 执行流程 代码 运行结果 可读性好的代码 2.前后指针法(双指针法) 执行流程 单趟排序代码 将单趟排序代码改造后 写法1 简洁的写法 3.思考题 1.挖坑法 执行流程 "挖坑法"顾名思义:要有坑位,一开始将关键值放入临时变量key中,在数组中形成…

JavaFx 21 项目Markdown 预览、编辑、新建、文件树、删除、重命名

项目文件结构 项目的源代码和资源文件存放在以下路径: 源代码: src/main/java/com/kong/markdown/ 包含多个 Java 文件,主要实现了应用的功能: App.java:主类,可能包含应用的启动逻辑。FileService.java:可能与文件操作相关的服务类。MainController.java:控制器类,可…

jenkins入门6 --拉取代码

Jenkins代码拉取 需要的插件,缺少的安装下 新建一个item,选择freestyle project 源码管理配置如下:需要添加git库地址,和登录git的用户密码 配置好后执行编译,成功后拉取的代码在工作空间里

数学建模入门——建模流程

摘要:本文介绍了数学建模的一般流程概述。 目录 一、前言 二、数据预处理 三、描述性统计分析 四、模型建立 五、模型评价 一、前言 本文将为想要入门数学建模的同学讲述数学建模的一般流程。但数学建模流程并非一成不变。虽有大致步骤,像分析问题、…

《机器学习》集成学习之随机森林

目录 一、集成学习 1、简介 2、集成学习的代表 3、XGBoost和随机森林的对比 相同点: 不同点: 二、Bagging之随机森林 1、简介 2、随机森林的核心思想 3、随机森林生成步骤 4、随机森林的优点 5、随机森林的缺点 三、随机森林的代码实现 1、…

【HarmonyOS NEXT】鸿蒙应用实现屏幕录制详解和源码

【HarmonyOS NEXT】鸿蒙应用实现屏幕录制详解和源码 一、前言 官方文档关于屏幕录制的API和示例介绍获取简单和突兀。使用起来会让上手程度变高。所以特意开篇文章,讲解屏幕录制的使用。官方文档参见:使用AVScreenCaptureRecorder录屏写文件(ArkTS) 二…

CSS——22.静态伪类(伪类是选择不同元素状态)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>静态伪类</title> </head><body><a href"#">我爱学习</a></body> </html>单击链接前的样式 左键单击&#xff08;且…

JavaWeb开发(六)XML介绍

1. XML介绍 1.1. 什么是XML &#xff08;1&#xff09;XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种很像HTML的标记语言。   &#xff08;2&#xff09;XML 的设计宗旨是传输数据(目前主要是作为配置文件)&#xff0c;而不是显示数据。   &#xff08;3&a…