当前位置: 首页 > news >正文

设计模式基础概念(行为模式):策略模式

概述

策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换

主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换

结构

在这里插入图片描述

示例

策略模式在 Java 代码中很常见。 它经常在各种框架中使用, 能在不扩展类的情况下向用户提供改变其行为的方式。

javax.servlet.http.HttpServlet: ​ service­()方法, 还有所有接受 Http­Servlet­Request和 Http­Servlet­Response对象作为参数的 do­XXX()方法。

识别方法: 策略模式可以 通过允许嵌套对象完成实际工作的方法,以及允许将该对象替换为不同对象的设置器来识别。

伪代码实现

strategies

策略(strategies)的定义:所有具体策略的通用接口, 它声明了一个上下文用于执行策略的方法

public interface PayStrategy {boolean pay(int paymentAmount);void collectPaymentDetails();
}

Concrete Strategies

具体策略 (Concrete Strategies): 实现上下文所用算法的各种不同变体。

PayByPayPal: 使用 PayPal 支付

public class PayByPayPal implements PayStrategy {@Overridepublic void collectPaymentDetails() {// todo}@Overridepublic boolean pay(int paymentAmount) {// todo}

PayByCreditCard: 使用信用卡支付

public class PayByCreditCard implements PayStrategy {@Overridepublic void collectPaymentDetails() {// todo}@Overridepublic boolean pay(int paymentAmount) {// todo}

Context

上下文 (Context): 维护指向具体策略的引用, 且仅通过策略接口与该对象进行交流。

public class Order {private int totalCost = 0;private boolean isClosed = false;// 提供一个计算的接口供客户端使用。public void processOrder(PayStrategy strategy) {strategy.collectPaymentDetails();// Here we could collect and store payment data from the strategy.}}

Client

客户端 (Client) 会创建一个特定策略对象并将其传递给上下文。

上下文则会提供一个设置器以便客户端在运行时替换相关联的策略。

public class Client {private static Map<Integer, Integer> priceOnProducts = new HashMap<>();private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));private static Order order = new Order();private static PayStrategy strategy;static {priceOnProducts.put(1, 2200);priceOnProducts.put(2, 1850);priceOnProducts.put(3, 1100);priceOnProducts.put(4, 890);}public static void main(String[] args) throws IOException {while (!order.isClosed()) {int cost;String continueChoice;do {System.out.print("Please, select a product:" + "\n" +"1 - Mother board" + "\n" +"2 - CPU" + "\n" +"3 - HDD" + "\n" +"4 - Memory" + "\n");int choice = Integer.parseInt(reader.readLine());cost = priceOnProducts.get(choice);System.out.print("Count: ");int count = Integer.parseInt(reader.readLine());order.setTotalCost(cost * count);System.out.print("Do you wish to continue selecting products? Y/N: ");continueChoice = reader.readLine();} while (continueChoice.equalsIgnoreCase("Y"));if (strategy == null) {System.out.println("Please, select a payment method:" + "\n" +"1 - PalPay" + "\n" +"2 - Credit Card");String paymentMethod = reader.readLine();// Client creates different strategies based on input from user,// application configuration, etc.if (paymentMethod.equals("1")) {strategy = new PayByPayPal();} else {strategy = new PayByCreditCard();}}// Order object delegates gathering payment data to strategy object,// since only strategies know what data they need to process a// payment.order.processOrder(strategy);System.out.print("Pay " + order.getTotalCost() + " units or Continue shopping? P/C: ");String proceed = reader.readLine();if (proceed.equalsIgnoreCase("P")) {// Finally, strategy handles the payment.if (strategy.pay(order.getTotalCost())) {System.out.println("Payment has been successful.");} else {System.out.println("FAIL! Please, check your data.");}order.setClosed();}}}
}

应用场景

当你想使用对象中各种不同的算法变体, 并希望能在运行时切换算法时, 可使用策略模式。

策略模式让你能够将对象关联至可以不同方式执行特定子任务的不同子对象, 从而以间接方式在运行时更改对象行为。

当你有许多仅在执行某些行为时略有不同的相似类时, 可使用策略模式。

策略模式让你能将不同行为抽取到一个独立类层次结构中, 并将原始类组合成同一个, 从而减少重复代码。

如果算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来。

策略模式让你能将各种算法的代码、 内部数据和依赖关系与其他代码隔离开来。 不同客户端可通过一个简单接口执行算法, 并能在运行时进行切换。

当类中使用了复杂条件运算符以在同一算法的不同变体中切换时, 可使用该模式。

策略模式将所有继承自同样接口的算法抽取到独立类中, 因此不再需要条件语句。 原始对象并不实现所有算法的变体, 而是将执行工作委派给其中的一个独立算法对象。

实现步骤

首先,从上下文类中找出修改频率较高的算法

其次,声明该算法所有变体的通用策略接口。将算法逐一抽取到各自的类中, 它们都必须实现策略接口。

之后,在上下文类中添加一个成员变量用于保存对于策略对象的引用

  • 然后提供设置器以修改该成员变量。
  • 上下文仅可通过策略接口同策略对象进行交互,
  • 如有需要还可定义一个接口来让策略访问其数据。

最后,客户端必须将上下文类与相应策略进行关联, 使上下文可以预期的方式完成其主要工作。

优缺点

策略模式优点:

  • 扩展性好,可以在不修改对象结构的情况下,为新的算法进行添加新的类进行实现;
  • 灵活性好,可以对算法进行自由切换;

策略模式缺点:

  • 使用策略类变多,会增加系统的复杂度。;
  • 客户端必须知道所有的策略类才能进行调用;
http://www.lryc.cn/news/620421.html

相关文章:

  • Swift 实战:用链表和哈希表写出高性能的贪吃蛇引擎(LeetCode 353)
  • LeetCode 刷题【41. 缺失的第一个正数】
  • linux 主机驱动(SPI)与外设驱动分离的设计思想
  • tomcat 定时重启
  • LeetCode 1780:判断一个数字是否可以表示成3的幂的和-进制转换解法
  • 【Java虚拟机】JVM相关面试题
  • 网页加载缓慢系统排查与优化指南
  • pnpm常用命令;为什么使用pnpm?
  • 【STM32入门教程】stm32简介
  • Day56--图论--108. 冗余的边(卡码网),109. 冗余的边II(卡码网)
  • QLab Pro for Mac —— 专业现场音频与多媒体控制软件
  • 【BFS】P9065 [yLOI2023] 云梦谣|普及+
  • Spark Shuffle机制原理
  • 云蝠智能 VoiceAgent:重构物流售后场景的智能化引擎
  • 标贝科技「十万音色·自然语音数据集」 重构AI语音训练基础设施
  • 基于vue.js的无缝滚动
  • 系统设计——DDD领域模型驱动实践
  • rustdesk 开源遥控软件
  • 【深度学习计算性能】04:硬件
  • 医疗AI问答系统实战:知识图谱+大模型的融合应用开发
  • Trae x Figma MCP一键将设计稿转化为精美网页
  • 【python】类型注解
  • CICD-Devops整合Kubernetes-4
  • 深入学习Autosar之BswM模块
  • 4.2 Vue3中reactive与ref详解及区别
  • 云计算-多服务集群部署实战指南:从JumpServer到Kafka、ZooKeeper 集群部署实操流程
  • 命名空间——网络(net)
  • 4.1vue3的setup()
  • EtherCAT概念介绍
  • 防抖 debounce.js