Java设计模式之策略模式详细讲解和案例示范

Java设计模式之策略模式详细讲解和案例示范

在软件开发中,策略模式是一种常见且非常有用的设计模式。它允许定义一系列算法,将它们一个个封装起来,并且使它们可以互相替换。策略模式让算法可以独立于使用它们的客户端而变化。本篇文章将详细介绍策略模式,包含它的应用场景、常见问题及解决方式,并会通过以电商交易系统为例子来说明。最后,我们还将对策略模式与工厂模式、适配器模式进行比较,探讨它们之间的区别。此外,还会介绍策略模式在开源框架中的实际应用。

一、策略模式的基本概念

策略模式(Strategy Pattern)定义了一系列算法,并将每个算法封装起来,使得它们可以互相替换。策略模式使得算法可以独立于使用它们的客户端而变化。策略模式的主要角色包括:

  1. Context(上下文):维护对某个策略对象的引用,用于客户端调用。
  2. Strategy(策略接口):定义策略方法,策略类都需要实现这个接口。
  3. ConcreteStrategy(具体策略类):实现策略接口,提供具体的算法实现。
    在这里插入图片描述
二、策略模式的使用场景

策略模式特别适用于以下场景:

  • 需要在多个算法中进行选择时:例如电商平台上的优惠券计算,有不同的计算方式,如满减、打折、返现等,可以使用策略模式将这些计算方式封装起来。
  • 算法的实现可以独立于使用它的客户类:例如,在订单结算过程中,可以根据不同的用户类型(会员、普通用户)选择不同的结算策略。
  • 算法需要在运行时根据不同条件动态切换:例如,电商系统中可以根据商品的种类选择不同的库存计算方式。
三、策略模式的电商交易系统示例

我们以电商交易系统中的“订单优惠计算”为例,来说明策略模式的应用。

  1. 定义策略接口
public interface DiscountStrategy {double calculateDiscount(Order order);
}
  1. 具体策略实现类
public class PercentageDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(Order order) {// 10%折扣return order.getTotalAmount() * 0.10;}
}public class FixedAmountDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(Order order) {// 固定减免50元return 50.0;}
}
  1. 上下文类
public class Order {private DiscountStrategy discountStrategy;public Order(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}public double getTotalAmount() {// 假设总金额为1000元return 1000.0;}public double calculateDiscount() {return discountStrategy.calculateDiscount(this);}
}
  1. 客户端使用
public class ECommercePlatform {public static void main(String[] args) {Order order = new Order(new PercentageDiscountStrategy());double discount = order.calculateDiscount();System.out.println("折扣金额: " + discount);order = new Order(new FixedAmountDiscountStrategy());discount = order.calculateDiscount();System.out.println("折扣金额: " + discount);}
}
四、常见问题及解决方式(附代码示例)
  1. 策略类过多的问题:在策略模式中,每个算法都需要一个具体的策略类,当策略较多时,可能会导致类的数量急剧增加。可以通过使用匿名内部类或Lambda表达式来简化代码,避免类爆炸。

    问题示例

    public class SeasonalDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(Order order) {return order.getTotalAmount() * 0.15;}
    }public class NewCustomerDiscountStrategy implements DiscountStrategy {@Overridepublic double calculateDiscount(Order order) {return order.getTotalAmount() * 0.20;}
    }
    

    解决方式

    通过使用匿名内部类或Lambda表达式,减少具体策略类的数量:

    public class ECommercePlatform {public static void main(String[] args) {Order order = new Order(o -> o.getTotalAmount() * 0.15);double discount = order.calculateDiscount();System.out.println("季节折扣金额: " + discount);order = new Order(o -> o.getTotalAmount() * 0.20);discount = order.calculateDiscount();System.out.println("新客户折扣金额: " + discount);}
    }
    
  2. Context类依赖具体策略类的问题:上下文类需要与具体的策略类耦合,可能会导致代码的灵活性降低。可以通过工厂模式来动态选择和生成具体策略类。

    问题示例

    public class Order {private DiscountStrategy discountStrategy;public Order(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}public double calculateDiscount() {return discountStrategy.calculateDiscount(this);}
    }
    

    解决方式

    使用工厂模式来动态生成策略实例:

    public class DiscountStrategyFactory {public static DiscountStrategy getStrategy(String strategyType) {if ("Percentage".equals(strategyType)) {return o -> o.getTotalAmount() * 0.10;} else if ("FixedAmount".equals(strategyType)) {return o -> 50.0;} else {throw new IllegalArgumentException("Unknown strategy type");}}
    }public class ECommercePlatform {public static void main(String[] args) {Order order = new Order(DiscountStrategyFactory.getStrategy("Percentage"));double discount = order.calculateDiscount();System.out.println("折扣金额: " + discount);}
    }
    
五、策略模式与工厂模式的区别

策略模式与工厂模式在某些场景中可以配合使用,但它们的目的和应用场景有所不同:

  • 策略模式:侧重于算法的替换,它封装了不同的算法或行为,使它们在不同的场景下可以互换。
  • 工厂模式:则用于创建对象,它解决了对象的实例化问题。

在策略模式中,算法已经存在,策略模式只是选择哪一个算法;而在工厂模式中,我们关注的是如何创建这些算法对应的对象。

六、策略模式与适配器模式的区别

策略模式与适配器模式在结构上有一定的相似性,但它们的意图完全不同:

  • 策略模式:用于替换算法,即可以在运行时替换算法的实现。
  • 适配器模式:用于将一个接口转化为另一个接口,它主要是为了兼容现有系统或库。
七、在开源框架中的应用示范

在Spring中,策略模式常用于任务调度、视图解析、事务管理等模块。我们以Resource接口的实现为例来说明策略模式的应用。

Resource接口

在Spring中,Resource接口用于统一资源访问。Spring提供了多种Resource实现,如UrlResourceClassPathResource等。开发者可以根据需要选择不同的资源访问策略。

public interface Resource {InputStream getInputStream() throws IOException;// 其他方法省略...
}public class UrlResource implements Resource {private final URL url;public UrlResource(URL url) {this.url = url;}@Overridepublic InputStream getInputStream() throws IOException {return url.openStream();}
}public class ClassPathResource implements Resource {private final String path;public ClassPathResource(String path) {this.path = path;}@Overridepublic InputStream getInputStream() throws IOException {return getClass().getClassLoader().getResourceAsStream(path);}
}

如何使用策略模式

在应用中,你可以选择合适的Resource实现来加载资源。例如,当你需要加载外部URL资源时,可以使用UrlResource;而加载类路径资源时,可以使用ClassPathResource

public class ResourceLoader {public void loadResource(Resource resource) {try (InputStream is = resource.getInputStream()) {// 处理输入流System.out.println("Resource Loaded: " + resource.toString());} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {ResourceLoader loader = new ResourceLoader();// 使用URL策略Resource urlResource = new UrlResource(new URL("http://example.com/data.txt"));loader.loadResource(urlResource);// 使用类路径策略Resource classPathResource = new ClassPathResource("data.txt");loader.loadResource(classPathResource);}
}
八、总结

策略模式是一个非常强大的设计模式,它使得算法可以在不同的上下文中灵活地替换。在电商交易系统中,策略模式可以用于实现各种复杂的业务逻辑,如优惠计算、库存管理等。通过策略模式,我们可以将不同的算法进行封装,并在运行时动态选择,从而使代码更加灵活、易于维护。同时,我们还探讨了策略模式与工厂模式、适配器模式的区别,并展示了在Spring框架中的实际应用。

通过这些内容,相信你对策略模式有了更加深入的理解,并能够在实际项目中灵活运用这一设计模式。如果你在项目中遇到类似的问题,可以尝试使用策略模式来解决,可能会有意想不到的效果。

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

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

相关文章

[MySql]保姆级上手教程

介绍 通过数据库管理系统, 编写执行SQL语句, 实现对数据库数据的管理 数据库(DataBase): 储存和管理数据的仓库数据库管理系统(DBMS): 操作和管理数据库的软件SQL语言: 操作关系型数据库的通用语言数据库可以分为关系型数据库和非关系型数据库 相关产品 常见的关系型数据库产…

【golang-入门】环境配置、VSCode开发环境配置

golang介绍基础信息 windows环境配置安装包下载安装环境变量设置检查 VSCode开发配置插件配置在 Visual Studio Code 中安装通义灵码go hello word 参考资料 golang介绍 基础信息 golang官网:https://go.dev/golang学习网:https://studygolang.com/使用…

android使用YOLOV8数据返回到JAVA方法(JAVA)

一、下载扩展文件(最耗时,所以放第一步) 1.opencv下载 1)官网:Releases - OpenCV 2)下载最新版本的android包 2.NCNN下载 1)NCNN下载地址(20220420版本):https://github.com/Tencent/ncnn/releases/download/20220420/ncnn-20220420-android-vulkan.zip 3.在你的…

【C++二分查找】2271. 毯子覆盖的最多白色砖块数

本文涉及的基础知识点 C二分查找 LeetCode2271. 毯子覆盖的最多白色砖块数 给你一个二维整数数组 tiles &#xff0c;其中 tiles[i] [li, ri] &#xff0c;表示所有在 li < j < ri 之间的每个瓷砖位置 j 都被涂成了白色。 同时给你一个整数 carpetLen &#xff0c;表…

使用 Jpom 自动化构建并部署项目

1、前言 Jpom 是一款专为开发者设计的轻量级运维工具。它提供了一整套从项目构建到自动部署&#xff0c;再到日常运维和项目监控的解决方案&#xff0c;帮助开发者更好地管理和维护项目。 Jpom 的目标是让开发者不再为复杂的运维流程头疼。它支持多种安装方式&#xff0c;灵活…

RoboCat: A Self-Improving Generalist Agent for Robotic Manipulation

发表时间&#xff1a;22 Dec 2023 论文链接&#xff1a;https://readpaper.com/pdf-annotate/note?pdfId4836882796542689281&noteId2413286807916664832 作者单位&#xff1a;Google DeepMind Motivation&#xff1a;受视觉和语言基础模型的最新进展的启发&#xff0c…

【教程】实测np.fromiter 和 np.array 的性能

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 函数简介 np.fromiter np.array 测试代码 实验结果 结果分析 实验总结 学长想说 函数简介 np.fromiter np.fromiter 是 NumPy 提供的一…

设计模式 -- 装饰者模式(Decorator Pattern)

1 问题引出 1.1 咖啡馆订单项目 咖啡种类/单品咖啡&#xff1a;Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡) 调料&#xff1a;Milk、Soy(豆浆)、Chocolate 要求在扩展新的咖啡种类时&#xff0c;具有良好的扩展性、改动方便、维护方便 使用…

无人机之云台的作用

无人机云台在无人机技术中扮演着至关重要的角色&#xff0c;其作用主要体现在以下几个方面&#xff1a; 一、 确保拍摄稳定性 防抖动&#xff1a;无人机在飞行过程中&#xff0c;尤其是在复杂环境下&#xff0c;如遇到风力干扰或进行高速飞行时&#xff0c;机身容易产生震动和…

Beyond Compare忽略特定格式文本,忽略匹配正则表达式

一 概述 文本对比时忽略某些文本。比如有些生成的文件需要做差异对比&#xff0c;除了内容有差异外&#xff0c;自动生成的ID也不同&#xff0c;想忽略这些ID。特别是文件内容比较多的时候。 如上图&#xff0c;其中UUID“*”的部分我想忽略。 二 方法 方法1 通过Beyond Co…

MySQL 中间件 MySQL-Router

目录 1 MySQL-Router 的介绍 2 MySQL-Router 负载均衡 2.1 设计目的&#xff1a; 2.2 HAProxy 与 Nginx 和 MySQL-Router 之间的区别 2.3 MySQL-Router 的优势 3 MySQL-Router 的获取 3 MySQL-Router 的使用 3.1 实验环境 3.2 MySQL-Router 部署 3.3 MySQL-Router 配置 3.4 测…

HarmonyOS--合理使用动画

一、概述 动画是应用开发中必不可少的部分&#xff0c;它可以使应用程序更加生动和易于互动&#xff0c;一方面可以提升用户体验、增强视觉吸引力&#xff0c;另一方面可以引导用户操作、提高信息传达效率。应用程序中&#xff0c;页面层级间的转场、点击交互、手势操控都可以添…

ODOO17文档打印(输出)方案 -- ODOO17 document printing (output) scheme

根据使用场景不同&#xff0c;ODOO17支持以下几种文档打印(输出)方案&#xff1a; According to different usage scenarios, ODOO17 supports the following document printing (output) schemes: 1、QWEB ODOO原生打印功能&#xff08;生成PDF文档&#xff09; odoo使用的主…

【AI】:探索在图像领域的无限可能

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 图像识别与分类的飞跃图像生成与创造的艺术图像增强与修复的神奇图像搜索与理解的智能图像分析与挖掘的洞察图形生成技术1. 生成对抗网络&#xff08;GANs&#xff09;2. 卷积神经网络&#xff08;CN…

多语言跨领域迁移学习的新框架:MAD-X

人工智能咨询培训老师叶梓 转载标明出处 多语言模型如mBERT和XLM-R通过零样本或少样本跨语言迁移极大地推动了低资源语言的NLP应用。但这些模型由于容量限制&#xff0c;对低资源语言和未见语言的迁移性能并不理想。为了解决这一问题&#xff0c;来自德国达姆施塔特工业大学、…

Stable Diffusion详解

文章目录 前言一、LDM原理二、模型结构三、模型训练与推理总结 前言 Stable Diffusion在图像生成方面取得了很大的成功&#xff0c;其核心原理是LDM&#xff08;Latent Diffusion Models&#xff09;&#xff0c;在论文《High-Resolution Image Synthesis with Latent Diffusio…

【数据结构】优先级队列 — 堆

文章目录 前言1. 优先级队列1.1 概念1.2 特性 2. 堆2.1 概念2.2 存储方式 3. 堆的模拟实现3.1 堆的创建3.2 堆的插入3.3 堆的删除 4. PriorityQueue4.1 注意事项4.2 构造器介绍4.3 常用方法介绍 5. 经典题型6. 结语 前言 我们之前学习过队列&#xff0c;它是遵循先进先出原则的…

halcon 深度学习软件工具安装以及用法

安装halcon 20版本以上得 以为这个版本以上得有异常检测&#xff0c;分割&#xff0c;分类&#xff0c;目标检测&#xff0c;都有 一、下载软件 可以再官网下载&#xff0c;但是官网要注册账号 下载区域: MVTec Software 不用官方的账号 就下载安装包 链接&#xff1a;http…

day13JS-MoseEvent事件

1. MouseEvent的类别 mousedown &#xff1a;按下键mouseup &#xff1a;释放键click &#xff1a;左键单击dblclick &#xff1a;左键双击contextmenu &#xff1a;右键菜单mousemove &#xff1a;鼠标移动mouseover : 鼠标经过 。 可以做事件委托&#xff0c;子元素可以冒泡…

使用Blender进行3D建模—基础操作笔记

Blender 3D 建模&#x1f680; 在博0阶段&#xff0c;目前已经完成立创EDA的PCB绘制的基础学习&#xff0c;树莓派的系统安装远程控制能学习&#xff0c;加上我本硕阶段学习的单片机和深度学习人工智能算法的知识&#xff0c;这里打算补上一块比较重要的能力拼图&#xff0c;就…