策略模式 详解 设计模式

策略模式

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装到具有共同接口的独立类中,并且使它们可以相互替换。 策略模式可以让算法的变化独立于使用算法的客户端。

主要解决: 在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

结构

策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。所有具体策略类都实现了该接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为
  • 环境/上下文(Context)类:持有一个策略类的引用,负责将客户端的请求委派给具体的策略对象

图例:

请添加图片描述

在 Java 中使用策略模式的写法:

  1. 定义策略接口:创建一个接口,用于定义所有具体策略类的公共行为
  2. 创建具体策略类:实现策略接口,并提供具体的算法实现。
  3. 创建上下文类:维护一个对策略接口的引用,并提供方法来设置和切换不同的具体策略类。
  4. 客户端使用:在客户端代码中,创建上下文对象,并设置具体的策略类,然后调用上下文对象的方法来执行具体的算法。
// 1. 定义策略接口
interface PaymentStrategy { 
    void pay(double amount);
}

// 2. 创建具体策略类
class AliPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via AliPay.");
    }
}

class WeChatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via WeChatPay.");
    }
}

// 3. 创建上下文类
class PaymentContext {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void makePayment(double amount) {
        paymentStrategy.pay(amount);
    }
}

// 4. 客户端使用
public class Main {
    public static void main(String[] args) {
        PaymentContext paymentContext = new PaymentContext();

        // 使用支付宝支付
        paymentContext.setPaymentStrategy(new AliPayStrategy());
        paymentContext.makePayment(100.0);

        // 使用微信支付
        paymentContext.setPaymentStrategy(new WeChatPayStrategy());
        paymentContext.makePayment(50.0);
    }
}

代码中创建了策略接口 PaymentStrategy 和两个具体策略类 AliPayStrategyWeChatPayStrategy。然后,创建了上下文类 PaymentContext,它维护了一个对策略接口的引用,并提供了设置和执行具体策略的方法。最后,在客户端 Main 类中,创建了 PaymentContext 的实例,并设置了具体的支付策略,然后进行支付操作。

使用场景:

  • 当有多个相关的类只有行为或算法上稍有不同的情况下,可以考虑使用策略模式。它将算法的变化独立封装到各自的策略类中,易于扩展和维护。

  • 一个系统需要动态地在几种算法中选择一种时,可以将这些行为封装成不同的策略类,并在需要时动态切换。

  • 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。

  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句

注意事项: 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

混合模式是指在策略模式中引入了简单工厂模式或者享元模式等其他设计模式,来减少策略类的数量,简化系统的结构。

举例来说,假设一个系统有多种支付方式,除了支付宝支付和微信支付之外,还有银行卡支付、信用卡支付等多种支付方式。如果每种支付方式都对应一个具体的策略类,随着支付方式的增加,策略类的数量会急剧增加,导致类膨胀问题。为了解决这个问题,可以引入简单工厂模式,将支付方式的创建交给一个工厂类来完成;同时,如果某些支付方式具有相似的功能,可以使用享元模式来共享相同的部分,减少策略对象的数量。

代码案例:

// 1. 定义策略接口
interface PaymentStrategy { 
    void pay(double amount);
}

// 2. 创建具体策略类
class AliPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via AliPay.");
    }
}

class WeChatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via WeChatPay.");
    }
}

class BankCardPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via BankCard.");
    }
}

class CreditCardPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via CreditCard.");
    }
}

// 3. 创建简单工厂类
class PaymentStrategyFactory {
    private static final Map<String, PaymentStrategy> strategies = new HashMap<>();

    static {
        strategies.put("AliPay", new AliPayStrategy());
        strategies.put("WeChatPay", new WeChatPayStrategy());
        // 可以添加更多支付方式的策略对象
    }

    public static PaymentStrategy getPaymentStrategy(String type) {
        return strategies.get(type);
    }
}

// 4. 客户端使用
public class Main {
    public static void main(String[] args) {
        PaymentStrategy aliPayStrategy = PaymentStrategyFactory.getPaymentStrategy("AliPay");
        aliPayStrategy.pay(100.0);

        PaymentStrategy weChatPayStrategy = PaymentStrategyFactory.getPaymentStrategy("WeChatPay");
        weChatPayStrategy.pay(50.0);

        PaymentStrategy bankCardPayStrategy = PaymentStrategyFactory.getPaymentStrategy("BankCard");
        bankCardPayStrategy.pay(80.0);

        PaymentStrategy creditCardPayStrategy = PaymentStrategyFactory.getPaymentStrategy("CreditCard");
        creditCardPayStrategy.pay(120.0);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统管理:虚拟机 Kali Linux 安装

目录 一、理论 1.Kali Linux 二、实验 1.虚拟机Kali Linux安装准备阶段 2.安装Kali Linux 2. Kali Linux 更换国内源 3. Kali Linux 设置固定IP 4. Kali Linux 开启SSH远程连接 5. MobaXterm远程连接 Kali Linux 三、问题 1.apt 命令 取代哪些 apt-get命令 一、理论…

Linux文本处理三剑客:awk

在Linux操作系统中&#xff0c;grep、sed、awk被称为文本操作“三剑客”&#xff0c;上两期中&#xff0c;我们将详细介绍grep、sed的基本使用方法&#xff0c;希望能够帮助到有需要的朋友&#xff0c;现在&#xff0c;我们继续学习awk。 虽然awk是一个Linux中常见的命令&…

C 嵌入式系统设计模式 17:静态优先级模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述嵌入式并发和资源管理模式之三…

Slicer学习笔记(六十五) 3DSlicer的医学图像数据增强扩展模块

1. 医学图像数据增强扩展模块 基于3D Slicer5.1.0 编写了一个测试医学图像的数据增强测试扩展模块。 扩展模块名&#xff1a;DataAugementation 项目地址&#xff1a;DataAugmentation 下载该项目后&#xff0c;可以将该扩展模块添加到3D Slicer的扩展中。 关于如何给3DSlicer…

【STA】多场景时序检查学习记录

单周期路径 建立时间时序检查 在时钟的有效沿到达触发器之前&#xff0c;数据应在一定时间内保持稳定&#xff0c;这段时间即触发器的建立 时间。满足建立时间要求将确保数据可靠地被捕获到触发器中。 建立时间检查是从发起触发器中时钟的第一个有效沿到捕获触发器中时钟后面…

萌新学习RSA第一天

文章来自NSSCTF工坊Xenny的课程 1.非对称加密 2.介绍RSA来源&#xff08;三位数学家名字开头&#xff09; 3.RSA数学基础 4.算法实现 from Crypto.Util.number import * #这个是关于RSA很多函数的库 p getPrime(512) #111RSA第一步&#xff1a;生成随机的51…

Sora学习(一):Sora技术路径整体认知

前文&#xff1a;最近跟着DataWhale组队学习这一期“Sora原理与技术实战”&#xff0c;本篇博客主要是基于DataWhale成员、厦门大学平潭研究院杨知铮研究员分享的Sora技术原理详解课件内容以及参考网上一些博客资料整理而来&#xff08;详见文末参考文献&#xff09;&#xff0…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:禁用控制)

组件是否可交互&#xff0c;可交互状态下响应点击事件、触摸事件、拖拽事件、按键事件、焦点事件和鼠标事件。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 enabled enabled(value: boolean) 设置组…

持续集成(CICD)- Git版本管理工具,Gitee线上仓库

文章目录 一、学习目标:二、什么是Git工具三 、Git环境搭建(windows系统)四、Gitee设置(私钥和公钥绑定)五、Git结合Gittee进行基本设置(重要)六、在Gitee上新建仓库私有仓库(非空仓库)七、Git拉取线上仓库代码,提交代码(重要)八、Git解决版本冲突问题(重要)场景一…

第二讲:用geth和以太坊交互

一&#xff1a;安装geth brew install ethereum geth github网址&#xff1a; https://github.com/ethereum/go-ethereum 二&#xff1a; 用geth连接以太坊 以太坊有主网络&#xff08;Ethereum Mainnet&#xff09;&#xff0c;有测试网络&#xff08;Sepolia、Goerli 等等…

leetcode 热题 100_盛最多水的容器

题解一&#xff1a; 双指针遍历&#xff1a;容量计算公式为min(左高度&#xff0c;右高度)*底部距离&#xff0c;我们可以令底部距离逐步递减&#xff08;左右两边的指针向中部移动&#xff09;。此时对于min(左高度&#xff0c;右高度)&#xff0c;假设较高的线向中部移动&…

如何修炼成“神医”——《OceanBase诊断系列》之一

本系列是基于OcenaBase 开发工程师在工作中的一些诊断经验&#xff0c;也欢迎大家分享相关经验。 1. 关于神医的故事 扁鹊&#xff0c;中国古代第一个被正史记载的医生&#xff0c;他的成才之路非常传奇。年轻时&#xff0c;扁鹊是一家客栈的主管。有一位名叫长桑君的客人来到…

HTTPS的实现原理

图片来源&#xff1a;HTTPS 详解一&#xff1a;附带最精美详尽的 HTTPS 原理图 - 个人文章 - SegmentFault 思否 加密流程按图中的序号分为&#xff1a; 客户端请求 HTTPS 网址&#xff0c;然后连接到 server 的 443 端口 (HTTPS 默认端口&#xff0c;类似于 HTTP 的80端口)。…

小程序和页面生命周期详解

目录 小程序的生命周期 创建&#xff08;onLoad&#xff09;&#xff1a; 显示&#xff08;onShow&#xff09;&#xff1a; 隐藏&#xff08;onHide&#xff09;&#xff1a; 卸载&#xff08;onUnload&#xff09;&#xff1a; 错误监听&#xff08;onError&#xff09;…

使用最新Hal库实现USART中断收发功能(STM32F4xx)

目录 概述 1 认识STM32F4XX的USART 1.1 USART 功能说明 1.2 USART的中断 1.3 USART 模式配置 1.4 USART的寄存器 2 使用STM32CubeMX 生成工程 2.1 配置参数 2.2 生成工程代码 3 实现软件功能 3.1 软件功能介绍 3.2 认识USART Hal库 3.2.1 初始化函数组 3.2.2 发送…

66-ES6:var,let,const,函数的声明方式,函数参数,剩余函数,延展操作符,严格模式

1.JavaScript语言的执行流程 编译阶段&#xff1a;构建执行函数&#xff1b;执行阶段&#xff1a;代码依次执行 2.代码块&#xff1a;{ } 3.变量声明方式var 有声明提升&#xff0c;允许重复声明&#xff0c;声明函数级作用域 访问&#xff1a;声明后访问都是正常的&…

殿堂级Flink源码极精课程预售

一、为什么我们要读源码? 1、让个人技术快速成长: 优秀的开源框架,底层的源码设计思想也非常优秀,同时还有含有大量的设计模式和并发编程技术&#xff0c;优秀的解决方案,熟读源码对猿们技术提升有很大帮助 2、新技术学习能力: Java开源码框架的源码熟读后&#xff0c;若出现…

挑战杯 基于机器视觉的车道线检测

文章目录 1 前言2 先上成果3 车道线4 问题抽象(建立模型)5 帧掩码(Frame Mask)6 车道检测的图像预处理7 图像阈值化8 霍夫线变换9 实现车道检测9.1 帧掩码创建9.2 图像预处理9.2.1 图像阈值化9.2.2 霍夫线变换 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分…

Doris实战——银联商务实时数仓构建

目录 前言 一、应用场景 二、OLAP选型 三、实时数仓构建 四、实时数仓体系的建设与实践 4.1 数仓分层的合理规划 4.2 分桶分区策略的合理设置 4.3 多源数据迁移方案 4.4 全量与增量数据的同步 4.5 离线数据加工任务迁移 五、金融级数仓稳定性最佳实践 5.1 多租户资…

返回数据(返回视图所需要的数据)

在上篇文章中&#xff0c;小编带领大家了解到&#xff1a;返回静态数据-CSDN博客&#xff0c;但是&#xff0c;仅仅返回一个静态页面&#xff0c;对于静态页面的数据没正常返回&#xff01; 所以&#xff0c;本篇文章便讲述如何返回数据&#xff1f;&#xff1f; 还是先不管前…