第十七章 策略模式

目录

1 策略模式概述

2 策略模式原理

 3 策略模式实现

4 策略模式应用实例

5 策略模式总结


1 策略模式概述

策略模式(strategy pattern)的原始定义是:定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。

2 策略模式原理

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

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境或上下文(Context)类:是使用算法的角色, 持有一个策略类的引用,最终给客户端调用。

 3 策略模式实现

/*** 抽象策略类* @author spikeCong* @date 2022/10/13**/
public interface Strategy {void algorithm();
}public class ConcreteStrategyA implements Strategy {@Overridepublic void algorithm() {System.out.println("执行策略A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void algorithm() {System.out.println("执行策略B");}
}/*** 环境类* @author spikeCong* @date 2022/10/13**/
public class Context {//维持一个对抽象策略类的引用private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}//调用策略类中的算法public void algorithm(){strategy.algorithm();}
}public class Client {public static void main(String[] args) {Strategy strategyA  = new ConcreteStrategyA();Context context = new Context(strategyA); //可以在运行时指定类型,通过配置文件+反射机制实现context.algorithm();}
}

4 策略模式应用实例

1 ) 不使用设计模式

  • 回执类
/*** 回执信息* @author spikeCong* @date 2022/10/13**/
public class Receipt {private String message; //回执信息private String type; //回执类型(MT1101、MT2101、MT4101、MT8104)public Receipt() {}public Receipt(String message, String type) {this.message = message;this.type = type;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public String getType() {return type;}public void setType(String type) {this.type = type;}
}
  • 回执生成器
public class ReceiptBuilder {public static List<Receipt> genReceiptList(){//模拟回执信息List<Receipt> receiptList = new ArrayList<>();receiptList.add(new Receipt("MT1101回执","MT1011"));receiptList.add(new Receipt("MT2101回执","MT2101"));receiptList.add(new Receipt("MT4101回执","MT4101"));receiptList.add(new Receipt("MT8104回执","MT8104"));//......return receiptList;}}
  • 客户端
public class Client {public static void main(String[] args) {List<Receipt> receiptList = ReceiptBuilder.genReceiptList();//循环判断for (Receipt receipt : receiptList) {if("MT1011".equals(receipt.getType())){System.out.println("接收到MT1011回执!");System.out.println("解析回执内容");System.out.println("执行业务逻辑A"+"\n");}else if("MT2101".equals(receipt.getType())){System.out.println("接收到MT2101回执!");System.out.println("解析回执内容");System.out.println("执行业务逻辑B"+"\n");}else if("MT4101".equals(receipt.getType())) {System.out.println("接收到MT4101回执!");System.out.println("解析回执内容");System.out.println("执行业务逻辑C"+"\n");}else if("MT8104".equals(receipt.getType())) {System.out.println("接收到MT8104回执!");System.out.println("解析回执内容");System.out.println("执行业务逻辑D");}//......}}
}

2 ) 使用策略模式进行优化

  • 策略接口
/*** 回执处理策略接口* @author spikeCong* @date 2022/10/13**/
public interface ReceiptHandleStrategy {void handleReceipt(Receipt receipt);
}
  • 具体策略类
public class Mt1011ReceiptHandleStrategy implements ReceiptHandleStrategy {@Overridepublic void handleReceipt(Receipt receipt) {System.out.println("解析报文MT1011: " + receipt.getMessage());}
}public class Mt2101ReceiptHandleStrategy implements ReceiptHandleStrategy {@Overridepublic void handleReceipt(Receipt receipt) {System.out.println("解析报文MT2101: " + receipt.getMessage());}
}......
  • 策略上下文类(策略接口的持有者)
/*** 上下文类,持有策略接口* @author spikeCong* @date 2022/10/13**/
public class ReceiptStrategyContext {private ReceiptHandleStrategy receiptHandleStrategy;public void setReceiptHandleStrategy(ReceiptHandleStrategy receiptHandleStrategy) {this.receiptHandleStrategy = receiptHandleStrategy;}//调用策略类中的方法public void handleReceipt(Receipt receipt){if(receipt != null){receiptHandleStrategy.handleReceipt(receipt);}}
}
  • 策略工厂
public class ReceiptHandleStrategyFactory {public ReceiptHandleStrategyFactory() {}//使用Map集合存储策略信息,彻底消除if...elseprivate static Map<String,ReceiptHandleStrategy> strategyMap;//初始化具体策略,保存到map集合public static void init(){strategyMap = new HashMap<>();strategyMap.put("MT1011",new Mt1011ReceiptHandleStrategy());strategyMap.put("MT2101",new Mt2101ReceiptHandleStrategy());}//根据回执类型获取对应策略类对象public static ReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){return strategyMap.get(receiptType);}
}
  • 客户端
public class Client {public static void main(String[] args) {//模拟回执List<Receipt> receiptList = ReceiptBuilder.genReceiptList();//策略上下文ReceiptStrategyContext context = new ReceiptStrategyContext();//策略模式将策略的 定义、创建、使用这三部分进行了解耦for (Receipt receipt : receiptList) {//获取置策略ReceiptHandleStrategyFactory.init();ReceiptHandleStrategy strategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());//设置策略context.setReceiptHandleStrategy(strategy);//执行策略context.handleReceipt(receipt);}}
}

5 策略模式总结

1) 策略模式优点:

  • 策略类之间可以自由切换

    由于策略类都实现同一个接口,所以使它们之间可以自由切换。

  • 易于扩展

    增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“

  • 避免使用多重条件选择语句(if else),充分体现面向对象设计思想。

2) 策略模式缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

3) 策略模式使用场景

  • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。

    策略模式最大的作用在于分离使用算法的逻辑和算法自身实现的逻辑,这样就意味着当我们想要优化算法自身的实现逻辑时就变得非常便捷,一方面可以采用最新的算法实现逻辑,另一方面可以直接弃用旧算法而采用新算法。使用策略模式能够很方便地进行替换。

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

    在实际开发中,有许多算法可以实现某一功能,如查找、排序等,通过 if-else 等条件判断语句来进行选择非常方便。但是这就会带来一个问题:当在这个算法类中封装了大量查找算法时,该类的代码就会变得非常复杂,维护也会突然就变得非常困难。虽然策略模式看上去比较笨重,但实际上在每一次新增策略时都通过新增类来进行隔离,短期虽然不如直接写 if-else 来得效率高,但长期来看,维护单一的简单类耗费的时间其实远远低于维护一个超大的复杂类。

  • 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。

    如果我们不希望客户知道复杂的、与算法相关的数据结构,在具体策略类中封装算法与相关数据结构,可以提高算法的保密性与安全性.

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

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

相关文章

java实现文件的压缩及解压

一、起因 开发中需要实现文件的压缩及解压功能&#xff0c;以满足某些特定场景的下的需要&#xff0c;在此说下具体实现。 二、实现 1.定义一个工具类ZipUtils,实现文件的压缩及解压&#xff0c;代码如下&#xff1a; import java.io.*; import java.nio.charset.Charset; impo…

TCPListen客户端和TCPListen服务器

创建项目 TCPListen服务器 public Form1() {InitializeComponent();//TcpListener 搭建tcp服务器的类&#xff0c;基于socket套接字通信的//1创建服务器对象TcpListener server new TcpListener(IPAddress.Parse("192.168.107.83"), 3000);//2 开启服务器 设置最大…

据阿谱尔统计显示,2023年全球凹版印刷机市场销售额约为9.1亿美元

根据阿谱尔 (APO Research&#xff09;的统计及预测&#xff0c;2023年全球凹版印刷机市场销售额约为9.1亿美元&#xff0c;预计在2024-2030年预测期内将以超过2.54%的CAGR&#xff08;年复合增长率&#xff09;增长。 由于对软包装和印刷包装的需求不断增长&#xff0c;全球凹…

数据分析-Excel基础函数的使用

Excel基础函数&#xff1a; sum:求和 sumif:单条件求和 sumifs:多条件求和 subtotal:根据筛选求和 if:逻辑判断 vlookup:连接匹配数据 match:查找数值在区域中的位置 index:根据区域的位置返回数值 match、index:一起使用&#xff1a;自动根据列名查找数据 sumifs、match、ind…

2.线性神经网络

目录 1.线性回归一个简化模型线性模型&#xff1a;可以看做是单层神经网络衡量预估质量训练数据参数学习显示解总结 2.基础优化方法小批量随机梯度下降总结 3.Softmax回归&#xff1a;其实是一个分类问题回归VS分类从回归到多类分类---均方损失Softmax和交叉熵损失 4.损失函数L…

web前端:作业三

1.回到顶部案例(固定定位) <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>#container{height: 5000px;border: 1px solid blue;}#back-button{width: 100px;height: 100px;border: 1px solid…

如何申请小程序SSL证书

在互联网时代&#xff0c;数据安全和用户隐私保护变得尤为重要。SSL证书作为网站、应用或小程序与用户之间建立安全连接的关键工具&#xff0c;其重要性不言而喻。SSL证书能够加密数据传输&#xff0c;防止信息被窃取&#xff0c;提升用户信任度&#xff0c;对于小程序开发者来…

Redux 与 MVI:Android 应用的对比

Redux 与 MVI&#xff1a;Android 应用的对比 在为 Android 应用选择合适的状态管理架构时可能会感到困惑。在这个领域中&#xff0c;有两种流行的选择是 Redux 和 MVI&#xff08;Model-View-Intent&#xff09;。两者都有各自的优缺点&#xff0c;因此在深入研究之前了解它们…

WebGIS开发:你还在纠结的10大问题合集!

问题1&#xff1a;GIS开发到底是学Java还是Python&#xff1f; Java是后端语言&#xff0c;Python更重数据分析和算法。 假设通常说的GIS开发是指Webgis&#xff0c;Web就是指网页端&#xff0c;所以我们说的GIS开发大部分情况下是指网页端的地图可视化开发。 GIS开发需要学…

工业烤箱设备厂家:专业制造,助力工业发展

随着现代工业的不断发展&#xff0c;工业烤箱设备在各个领域的应用越来越广泛。作为专业的工业烤箱设备厂家&#xff0c;我们致力于为客户提供高质量、高效率的烤箱设备&#xff0c;助力工业生产的顺利进行。 工业烤箱设备在工业生产中扮演着至关重要的角色。无论是电子、化工、…

Flask快速入门

Flask快速入门&#xff08;路由、CBV、请求和响应、session&#xff09; 目录 Flask快速入门&#xff08;路由、CBV、请求和响应、session&#xff09;安装创建页面Debug模式快速使用Werkzeug介绍watchdog介绍快速体验 路由系统源码分析手动配置路由动态路由-转换器 Flask的CBV…

SpringBoot整合SpringDataRedis

目录 1.导入Maven坐标 2.配置相关的数据源 3.编写配置类 4.通过RedisTemplate对象操作Redis SpringBoot整合Redis有很多种&#xff0c;这里使用的是Spring Data Redis。接下来就springboot整合springDataRedis步骤做一个详细介绍。 1.导入Maven坐标 首先&#xff0c;需要导…

Mysql中使用where 1=1有什么问题吗

昨天偶然看见一篇文章&#xff0c;提到说如果在mysql查询语句中&#xff0c;使用where 11会有性能问题&#xff1f;&#xff1f; 这着实把我吸引了&#xff0c;因为我项目中就有不少同事&#xff0c;包括我自己也有这样写的。为了不给其他人挖坑&#xff0c;赶紧学习一下&…

ABAP调用JavaScript进行幂乘运算

ECC版本没有内置的ipow运算函数&#xff0c;所以需要进行幂乘运算的话&#xff0c;可以采用调用JavaScript的方式来实现&#xff0c;参考代码如下&#xff1a;

集合java

1.集合 ArrayList 集合和数组的优势对比&#xff1a; 长度可变 添加数据的时候不需要考虑索引&#xff0c;默认将数据添加到末尾 package com.itheima;import java.util.ArrayList;/*public boolean add(要添加的元素) | 将指定的元素追加到此集合的末尾 | | p…

Chrome/Edge浏览器视频画中画可拉动进度条插件

目录 前言 一、Separate Window 忽略插件安装&#xff0c;直接使用 注意事项 插件缺点 1 .无置顶功能 2.保留原网页&#xff0c;但会刷新原网页 3.窗口不够美观 二、弹幕画中画播放器 三、失败的尝试 三、Potplayer播放器 总结 前言 平时看一些视频的时候&#xff…

Linux——自动化运维ansibe

一、自动化运维定义 自动化--- 自动化运维&#xff1a; 服务的自动化部署操作系统的日常运维&#xff1a;日志的备份、临时文件清理、服务器日常状态巡检、&#xff08;几乎包括了linux服务管理、linux 系统管理以及在docker 容器课程中涉及的所有内容&#xff09;服务架构的…

maven学习小结

背景 大佬指路我负责实践 目录结构 maven为项目提供一个标准目录结构 环境配置 下载maven包后解压&#xff0c;配置解压目录的bin到path变量&#xff0c;然后终端mvn -v&#xff0c;有回显则表明maven安装成功 pom POM&#xff0c;Project Object Model&#xff0c;项目对…

01_简单信号的连续和离散形式(2)

1. 单位阶跃信号 1.1离散 离散单位阶跃信号&#xff0c;也称为单位阶跃序列&#xff0c;是一个在离散时间信号分析中基础且重要的信号&#xff0c;用于描述在某个时间点后信号值发生突变的情形。它的定义如下&#xff1a; 离散单位阶跃信号具有以下几个重要性质和应用&#x…

Django中使用下拉列表过滤HTML表格数据

在Django中&#xff0c;你可以使用下拉列表&#xff08;即选择框&#xff09;来过滤HTML表格中的数据。这通常涉及两个主要步骤&#xff1a;创建过滤表单和处理过滤逻辑。 创建过滤表单 首先&#xff0c;你需要创建一个表单&#xff0c;用于接收用户选择的过滤条件。这个表单可…