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

设计模式笔记_行为型_策略模式

1. 策略模式介绍

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换。这种模式使得算法可以在不影响客户端的情况下发生变化。

类比场景:可以将策略模式类比为选择出行方式的场景。假设你要从一个城市到另一个城市,你可以选择不同的出行方式,比如开车、坐火车、或者乘飞机。每种方式都有自己的优缺点,但最终目的是到达目的地。策略模式就像是为你提供了一种机制来选择最适合当前情况的出行方式。

结构:策略模式通常由以下几个部分组成:

  1. 策略接口(Strategy Interface):定义了一个通用接口,所有具体策略类都实现这个接口。
  2. 具体策略类(Concrete Strategy Class):实现策略接口,提供具体的算法。
  3. 上下文类(Context Class):持有一个策略接口的引用,负责动态地选择和执行某个具体策略。上下文类在策略模式中扮演着一个重要角色,它不仅负责持有策略对象,还可能包含一些与策略相关的状态信息或辅助方法,以便于策略的执行。

优点:

  • 灵活性:可以根据需要在运行时动态地改变对象的算法或行为。
  • 扩展性:增加新的策略时,只需添加新的策略类即可,无需修改已有代码。
  • 简化代码:将算法的实现和使用分离,使代码更加简洁和易于维护。

2. 代码演示

场景:模拟出行方式,有开车、坐火车、或者乘飞机三种出行策略。

2.1 常规用法

策略接口(Strategy Interface):

public interface TravelStrategy {void travel();
}

具体策略类(Concrete Strategy Class):

// 具体策略类 - 开车
public class CarTravelStrategy implements TravelStrategy {@Overridepublic void travel() {System.out.println("Traveling by car.");}
}// 具体策略类 - 火车
public class TrainTravelStrategy implements TravelStrategy {@Overridepublic void travel() {System.out.println("Traveling by train.");}
}// 具体策略类 - 飞机
public class PlaneTravelStrategy implements TravelStrategy {@Overridepublic void travel() {System.out.println("Traveling by plane.");}
}

上下文类(Context Class):

public class TravelContext {private TravelStrategy strategy;//一些与策略相关的信息private String travelTime;public TravelContext(String travelTime) {this.travelTime = travelTime;}public void setStrategy(TravelStrategy strategy) {this.strategy = strategy;}public void executeTravel() {System.out.println("Travel time: " + travelTime);strategy.travel();}
}

客户端代码:使用策略模式

public class StrategyPatternDemo {public static void main(String[] args) {TravelContext context = new TravelContext("Morning");// 使用开车策略context.setStrategy(new CarTravelStrategy());context.executeTravel();// 使用火车策略context.setStrategy(new TrainTravelStrategy());context.executeTravel();// 使用飞机策略context.setStrategy(new PlaneTravelStrategy());context.executeTravel();}
}

对应的类图:

2.2 使用策略工厂优化

上述常规用法中,策略对象的创建比较简单,客户端在使用策略时顺手创建了对象。如果策略创建逻辑比较复杂,这种用法会增加客户端的复杂度,此时可以使用策略工厂优化。

策略工厂并不是策略模式的必需部分,但它可以在某些场景下增加策略模式的灵活性和可维护性。策略工厂的主要作用是负责创建策略对象,这样可以将策略的选择逻辑封装起来,使得客户端代码更简洁,并且可以更容易地管理和扩展策略。

引入策略工厂后,只需修改上下文类和客户端代码,其他保持不变。

新增策略工厂(StrategyFactory): 

public class TravelStrategyFactory {public static TravelStrategy getStrategy(String preference) {switch (preference.toLowerCase()) {case "car":return new CarTravelStrategy();case "train":return new TrainTravelStrategy();case "plane":return new PlaneTravelStrategy();default:throw new IllegalArgumentException("Unknown travel preference: " + preference);}}
}

上下文类(Context Class)修改如下:

public class TravelContext {private TravelStrategy strategy;private String travelTime;public TravelContext(String travelTime) {this.travelTime = travelTime;}//根据用户选择的交通工具名称,使用策略工厂获取对应策略public void setStrategy(String preference) {this.strategy = TravelStrategyFactory.getStrategy(preference);}public void executeTravel() {System.out.println("Travel time: " + travelTime);strategy.travel();}
}

客户端代码修改如下:

public class StrategyPatternDemo {public static void main(String[] args) {TravelContext context = new TravelContext("Morning");// 使用开车策略; 直接传入交通工具名称即可context.setStrategy("car");context.executeTravel();// 使用火车策略context.setStrategy("train");context.executeTravel();// 使用飞机策略context.setStrategy("plane");context.executeTravel();}
}

对应的类图:

引入策略工厂的优点:

  1. 封装选择逻辑:策略工厂将策略选择的逻辑集中在一个地方,使得上下文或客户端代码更简洁。
  2. 易于扩展:当需要添加新的策略时,只需更新工厂的创建逻辑,而不需要修改上下文或客户端代码。
  3. 减少耦合:上下文或客户端代码与具体策略的创建解耦,使得代码更易于维护。

虽然策略工厂不是策略模式的核心部分,但在一些复杂的场景中,它可以显著提高代码的组织性和可维护性。根据项目需求和复杂度,可以选择是否使用策略工厂。

http://www.lryc.cn/news/619763.html

相关文章:

  • OpenJDK 17 源码 安全点轮询的信号处理流程
  • 资源查看-lspci命令
  • 如何准备一场技术演讲
  • 各种排序算法(二)
  • 磁悬浮轴承转子设计避坑指南:深度解析核心要点与高可靠性策略
  • 基于js和html的点名应用
  • 【电气】NPN与PNP
  • B系列树详细讲解
  • 16-docker的容器监控方案-prometheus实战篇
  • Python 类元编程(导入时和运行时比较)
  • Windows也能用!Claude Code硬核指南
  • [激光原理与应用-259]:理论 - 几何光学 - 平面镜的反射、平面透镜的折射、平面镜的反射成像、平面透镜的成像的规律
  • 网刻软件iVentoy软件使用方法
  • @进程管理工具 - Glances工具详细指南
  • Django REST Framework视图
  • Java 大视界 -- Java 大数据机器学习模型在金融资产配置优化与风险收益平衡中的应用(395)
  • 解惑rust中的 Send/Sync(译)
  • 基于Java的Markdown转Word工具(标题、段落、表格、Echarts图等)
  • 18.10 SQuAD数据集实战:5步高效获取与预处理,BERT微调避坑指南
  • 实战多屏Wallpaper壁纸显示及出现黑屏问题bug分析-学员作业
  • HTML <iframe> 标签 如何把html写入iframe标签
  • 版图设计学习2_掌握PDK中的层定义(工艺文档精读)
  • Spring Boot 集成 机器人指令中枢ROS2工业机械臂控制网关
  • 如何在 Spring Boot 中设计和返回树形结构的组织和部门信息
  • 大致计算服务器磁盘使用情况脚本
  • GNhao/GN号,海外SIM号怎么获取的步骤指南
  • npm install 的作用
  • Android实现Glide/Coil样式图/视频加载框架,Kotlin
  • 【KO】Android 网络相关面试题
  • 华为 HCIE 大数据认证中 Linux 命令行的运用及价值