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

设计模式-行为型模式-策略模式

一、什么是策略模式

        策略模式是一种行为设计模式,它允许在运行时选择算法或行为,并将其封装成独立的对象,使得这些算法或行为可以相互替换,而不影响使用它们的客户端。(ChatGPT生成)

        主要组成部分:

        1、策略(Strategy): 定义了一个算法族、行为或方法,并将其封装在一个接口或抽象类中,使得这些算法可以相互替换。

        2、具体策略(Concrete Strategy): 实现了策略接口,提供了具体的算法或行为实现。

        3、上下文(Context): 持有一个策略对象的引用,在运行时可动态切换不同的策略。

        原理:

        1、策略模式允许在运行时动态选择算法或行为,通过将具体的算法或行为封装成策略对象,然后将这些策略对象注入到上下文中。

        2、上下文根据不同的需求或条件选择合适的策略对象,并使用它执行特定的算法或行为。

        优点:

        1、易于扩展和维护: 可以方便地添加新的策略或修改现有策略,不影响原有代码。

        2、避免条件语句: 可以避免大量的条件语句,提高代码可读性和可维护性。

        3、代码复用: 可以通过共享策略对象来提高代码的复用性。

二、场景模拟

        为了应用策略模式,我们模拟一个场景。在一个企业资源管理(ERP)系统中,可能会涉及到成本的计算,其中需要计算的成本例如:钢材、油漆、人工、运输等等,虽然说计算成本都是“单价*数量”,但是有些成本,例如钢材,不仅要计算钢材的成本,而且放置钢材或者其它费用,也需要进行一定的计费;对于人工成本,还需要计算企业担负的五险一金等。

 如上图所示,钢材是由吨数*单价计算的,但是要考虑保管费或其他费用,假设一吨n元,后续还可能考虑其它费用等;人工费用,雇员一人可能工资12000元,公司要负担其12%公积金或者医疗保险等;运输要考虑车辆维护费或者日常损耗。(以上仅是模拟,真实环境可能更加复杂或简单)。

三、业务实现

3.1、使用IF-ELSE方法

public static BigDecimal useIfElse(String name, BigDecimal amount, BigDecimal price){if (name.equals("plate")) {// 单价×数量,再加上每吨200元的其它费用return amount.multiply(price).add(amount.multiply(new BigDecimal("200.00")));} else if (name.equals("paints")) {// 单价×数量,再加上每吨200元的其它费用return amount.multiply(price).add(amount.multiply(new BigDecimal("100.00")));} else if (name.equals("employer")) {// 人员×数量,再加上每吨200元的其它费用BigDecimal sum = amount.multiply(price); // 基本工资sum = sum.add(amount.multiply(price.multiply(new BigDecimal("0.12")))); // 加上额外支付的12%公积金return sum;} else if (name.equals("haulage")) {// 吨数×数量,再加上每吨300元的损耗费用return amount.multiply(price).add(amount.multiply(new BigDecimal("300.00")));} else {log.error("无法匹配");return new BigDecimal(0);}}

我们用IF-ELSE方法,确实是可以实现功能,可以看出来很麻烦,看起来很混乱,没有结构,也没办法实现一些定制功能,后续变动起来也比骄困难,因为有一些东西都是写死的。我们来测试一下:

public static void main(String[] args) {// 钢板单价及数量BigDecimal plateAmount = new BigDecimal(15);BigDecimal platePrice = new BigDecimal("888.88");// 油漆价格及数量BigDecimal paintsAmount = new BigDecimal(20);BigDecimal paintsPrice = new BigDecimal("490.00");// 雇员工资及人数BigDecimal employerAmount = new BigDecimal(10);BigDecimal employerPrice = new BigDecimal("10000.00");// 运输价格及吨数BigDecimal haulageAmount = new BigDecimal(25);BigDecimal haulagePrice = new BigDecimal("3000.00");// 计算各个成本BigDecimal plate = useIfElse("plate", plateAmount, platePrice);BigDecimal paints = useIfElse("paints", paintsAmount, paintsPrice);BigDecimal employer = useIfElse("employer", employerAmount, employerPrice);BigDecimal haulage = useIfElse("haulage", haulageAmount, haulagePrice);BigDecimal sum = plate.add(paints).add(employer).add(haulage);log.info("钢材:{}元,油漆{}元,雇员:{}元,运输:{}元,总计:{}元", plate, paints, employer, haulage, sum);}

可以看到确实正确的计算出了结果,但是这种方式不具有拓展性,随着程序功能的增加,会越来越混乱。那有些同学可能会说,为什么不用Switch-Case方法?那就来实践一下。

3.2、使用Switch-Case方法

public static BigDecimal useSwitch(String name, BigDecimal amount, BigDecimal price){switch (name) {case "plate":// 单价×数量,再加上每吨200元的其它费用return amount.multiply(price).add(amount.multiply(new BigDecimal("200.00")));case "paints":// 单价×数量,再加上每吨200元的其它费用return amount.multiply(price).add(amount.multiply(new BigDecimal("100.00")));case "employer":// 人员×数量,再加上每吨200元的其它费用BigDecimal sum = amount.multiply(price); // 基本工资sum = sum.add(amount.multiply(price.multiply(new BigDecimal("0.12")))); // 加上额外支付的12%公积金return sum;case "haulage":// 吨数×数量,再加上每吨300元的损耗费用return amount.multiply(price).add(amount.multiply(new BigDecimal("300.00")));default:log.error("无法匹配");return new BigDecimal(0);}}

使用Switch-Case方法后,确实代码变得比较清晰了,但是一些东西仍然是写死的,不具备很好的扩展性。

3.3、使用策略模式重构代码

        其中ICosts是一个接口,里面只有一个方法,就是成本的计算。他的实现类包含钢材、油漆、人工等等,可以有很多。Context是策略控制类,外部可以传递不同策略执行计算成本方法。

 3.3.1、编写成本计算接口

public interface ICosts<T, K, V> {/*** 成本计算* @param amount 数量* @param price 单价* @param other 其它信息* @return 成本金额*/BigDecimal calculateCosts(T amount, BigDecimal price, Map<K, V> other);
}

 解释一下amount为什么要用T表示,因为这里数量不仅仅是BigDecimal形式的,可能会涉及到人、车辆等等,这种是没有小数点的……;关于other就是一些附加信息,例如钢材的除锈费用、维护费用,人员的五险一金比例等等。

3.3.2、具体成本实现类

钢材

public class GCCosts implements ICosts<BigDecimal, String, BigDecimal> {/** 钢材成本*   1、基本成本:吨数 * 价格;*   2、存放成本:吨数 * 存放消费;*   3、防锈成本:吨数 * 防锈成本;* */@Overridepublic BigDecimal calculateCosts(BigDecimal amount, BigDecimal price, Map<String, BigDecimal> other) {BigDecimal sum = amount.multiply(price);// 计算存放成本if (other.containsKey("CF")) {sum = sum.add(amount.multiply(other.get("CF")));}// 计算防锈成本if (other.containsKey("CX")) {sum = sum.add(amount.multiply(other.get("CX")));}return sum;}
}

油漆

public class YQCosts implements ICosts<BigDecimal, String, BigDecimal> {/** 油漆成本*   1、基础成本:单价 * 数量;*   2、存放成本: 数量 * 存放费用;* */@Overridepublic BigDecimal calculateCosts(BigDecimal amount, BigDecimal price, Map<String, BigDecimal> other) {BigDecimal sum = amount.multiply(price);if (other.containsKey("CF")) {sum = sum.add(amount.multiply(other.get("CF")));}return sum;}
}

人工

public class RGCosts implements ICosts<Long, String, BigDecimal> {/** 人工成本:*   1、基础成本:人数 * 工资;*   2、公积金成本: 人数 * (工资 * 公积金比例);*   3、五险成本:人数 * (工资 * 企业分摊比例);* */@Overridepublic BigDecimal calculateCosts(Long amount, BigDecimal price, Map<String, BigDecimal> other) {// 先计算每个人成本BigDecimal personCosts = price;// 加公积金if (other.containsKey("GJJ")) {personCosts = personCosts.add(price.multiply(other.get("GJJ")));}// 加五险if (other.containsKey("BX")) {personCosts = personCosts.add(price.multiply(other.get("BX")));}return personCosts.multiply(BigDecimal.valueOf(amount)); // 计算总成本}
}

运输

public class YSCosts implements ICosts<BigDecimal, String, BigDecimal> {/** 运输成本:*   1、基础成本:运输数量 * 运输单价;*   2、损耗费用:例如换机油,养护等费用,固定金额(模拟);* */@Overridepublic BigDecimal calculateCosts(BigDecimal amount, BigDecimal price, Map<String, BigDecimal> other) {BigDecimal sum = amount.multiply(price);// 加上固定的养护费用if (other.containsKey("YH")) {sum = sum.add(other.get("YH"));}return sum;}
}

3.3.3、成本策略控制类

public class CostsContext<T, K, V>{private ICosts<T, K, V> iCosts;public CostsContext(ICosts<T, K, V> iCosts) {this.iCosts = iCosts;}public BigDecimal calculateCosts(T amount, BigDecimal price, Map<K, V> other) {return iCosts.calculateCosts(amount, price, other);}
}

此类充当一个调度作用,不同的成本计算就选择不同的实现类,然后执行calculateCosts()方法。

3.3.4、测试

public static void main(String[] args) {// 钢板单价及数量BigDecimal plateAmount = new BigDecimal(15);BigDecimal platePrice = new BigDecimal("888.88");Map<String, BigDecimal> plateMap = new HashMap<String, BigDecimal>(){{put("CF", new BigDecimal("300"));put("CX", new BigDecimal("200"));}};// 油漆价格及数量BigDecimal paintsAmount = new BigDecimal(20);BigDecimal paintsPrice = new BigDecimal("490.00");Map<String, BigDecimal> paintsMap = new HashMap<String, BigDecimal>(){{put("CF", new BigDecimal("300"));}};// 雇员工资及人数// BigDecimal employerAmount = new BigDecimal(10);Long employerAmount = 10L;BigDecimal employerPrice = new BigDecimal("10000.00");Map<String, BigDecimal> employerMap = new HashMap<String, BigDecimal>(){{put("GJJ", new BigDecimal("0.12"));put("BX", new BigDecimal("0.06"));}};// 运输价格及吨数BigDecimal haulageAmount = new BigDecimal(25);BigDecimal haulagePrice = new BigDecimal("3000.00");Map<String, BigDecimal> haulageMap = new HashMap<String, BigDecimal>(){{put("YH", new BigDecimal("1500"));}};// 使用策略模式计算// 钢材CostsContext<BigDecimal, String, BigDecimal> plateCost = new CostsContext<>(new GCCosts());BigDecimal plate = plateCost.calculateCosts(plateAmount, platePrice, plateMap);// 油漆CostsContext<BigDecimal, String, BigDecimal> paintsCost = new CostsContext<>(new YQCosts());BigDecimal paints = paintsCost.calculateCosts(paintsAmount, paintsPrice, paintsMap);// 人工CostsContext<Long, String, BigDecimal> employerCost = new CostsContext<>(new RGCosts());BigDecimal employer = employerCost.calculateCosts(employerAmount, employerPrice, employerMap);// 运输CostsContext<BigDecimal, String, BigDecimal> haulageCost = new CostsContext<>(new YQCosts());BigDecimal haulage = haulageCost.calculateCosts(haulageAmount, haulagePrice, haulageMap);BigDecimal sum = plate.add(paints).add(employer).add(haulage);log.info("钢材:{}元,油漆{}元,雇员:{}元,运输:{}元,总计:{}元", plate, paints, employer, haulage, sum);}

上面是一些各种成本的数量和单价信息,同时使用Map存放了一些特有的成本信息,然后下面我们使用成本策略控制类CostsContext装载不同的实现类来进行成本的计算。

可以看到成功的计算出了结果。我们不仅实现了功能,也为后续的扩展打下了良好的基础,例如后续加新的成本类型进行计算,我们只需要继承ICosts实现不同的方法即可,如果某一个类型的计算加了一些条件,这样我们直接在Map里面添加条件,并在相应的实体类进行处理即可,这样让我们的代码结构变得清晰。

四、小结 

        if-else是我们初学代码时就接触到的代码,伴随我们走过了很多年,但是我们的思维一定要有提高,不要一有需求,就想到if-else,确实,if-else可以快速地实现功能,我们不可否认,但是随着项目复杂度的提高,if-else已经无法满足我们的需求,它会让我们的代码变得臃肿、复杂、结构混乱,所以我们就想到要用其它方法来替代if-else,让我们整个代码结构变得清晰。

        上面我们介绍了使用策略模式来代替一堆的if-else,策略模式的优点远不止如此:

        1、具有强的扩展性,例如我们扩充新的成本计算,只需要新建类并实现接口即可;

        2、易维护和理解,如何我么要看或者修改钢材的成本计算,我们不用到一堆if-else里面去找具体的代码块,我们只需要进去相应的实现类去看就可以,代码清晰明了,没有其他代码的干扰(体现出隔离性),我们维护起来也得心应手;

        3、使用策略模式可以让我们代码变得优美,思维能力和架构水平得到提升。

相关文章:

设计模式-行为型模式-策略模式

一、什么是策略模式 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法或行为&#xff0c;并将其封装成独立的对象&#xff0c;使得这些算法或行为可以相互替换&#xff0c;而不影响使用它们的客户端。&#xff08;ChatGPT生成&#xff09; 主要组成部分&#xff…...

ResizeObserver观察元素宽度的变化

ResizeObserver观察元素宽度的变化 ResizeObserver观察元素宽度的变化 ResizeObserver观察元素宽度的变化 ResizeObserver 构造函数创建一个新的 ResizeObserver 对象&#xff0c;它可以用于监听 Element 内容盒或边框盒或者 SVGElement 边界尺寸的大小。查看详细说明 案例 &l…...

斐波那契数列,剑指offer,力扣

目录 题目地址&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 难度分析&#xff1a; 审题目事例提示&#xff1a; 解题思路&#xff08;动态规划&#xff09;&#xff1a; 代码实现&#xff1a; 补充说明&#xff1a; 代码&#xff08;优化&#xff09;&…...

Mac安装CocoaPods

安装HomeBrew 安装 % /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装失败 % /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"curl: (28) F…...

APP专项测试方法和工具的使用(测试新手必看)

APP专项测试 1、网络测试 可使用抓包工具辅助网格测试推荐&#xff1a;fiddler&#xff0c;Charles &#xff08;1&#xff09;网络切换2G-3G-4G-wifi-网络信号差--无网&#xff08;2&#xff09;网络信号弱关注是否出现ANR、crash 2、中断测试 &#xff08;1&#xff09;…...

WordPress网站迁移实战经验

前几日,网站服务器到期,换了服务商,就把我的WordPress的网站迁移到本地电脑了。方便以后文章迁移。 本次迁移网站主要经历以下几个步骤。 1.域名转出。 2.备份数据库及网站文件下载。 3.重新搭建WordPress网站。 4.网站文件及数据库导入。 下面详细介绍下每个步骤的操作…...

3D全景视角,足不出户感知真实场景的魅力

近年来&#xff0c;随着科技的快速发展&#xff0c;普通的平面静态视角已经无法满足我们了&#xff0c;不管是视角框架的限制还是片面的环境展示&#xff0c;都不足以让我们深入了解场景环境。随着VR全景技术的日益成熟&#xff0c;3D全景技术的出现为我们提供了全新的视觉体验…...

C编译环境和预处理(非常详细,建议收藏)

C编译环境和预处理&#xff08;非常详细&#xff0c;建议收藏&#xff09; 一、程序的翻译环境和执行环境二、 详解编译链接2.1 翻译环境2.2 编译本身的几个阶段符号汇总、符号表、合并段表、符号表的合并和重定位分别是什么&#xff1f; 2.2 运行环境 三、预处理详解3.1 预定义…...

LeetCode669. Trim a Binary Search Tree

文章目录 一、题目二、题解 一、题目 Given the root of a binary search tree and the lowest and highest boundaries as low and high, trim the tree so that all its elements lies in [low, high]. Trimming the tree should not change the relative structure of the …...

YOLOv8优化策略:轻量级Backbone改进 | VanillaNet极简神经网络模型 | 华为诺亚2023

🚀🚀🚀本文改进:一种极简的神经网络模型 VanillaNet,支持vanillanet_5, vanillanet_6, vanillanet_7, vanillanet_8, vanillanet_9, vanillanet_10, vanillanet_11等版本 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,…...

【数据结构(二)】稀疏 sparsearray 数组(1)

文章目录 1. 稀疏数组的应用场景1.1. 一个实际的需求1.2. 基本介绍 2. 稀疏数组转换的思路分析3. 稀疏数组的代码实现3.1. 二维数组转稀疏数组3.2. 稀疏数组转二维数组 4. 课后练习 1. 稀疏数组的应用场景 1.1. 一个实际的需求 问题&#xff1a;     编写的五子棋程序中&…...

MySQL的执行器是怎么工作的

作为优化器后的真正执行语句的层&#xff0c;执行器有三种方式和存储引擎&#xff08;一般是innoDB&#xff09;交互 主键索引查询 查询的条件用到了主键&#xff0c;这个是全表唯一的&#xff0c;优化器会选择const类型来查询&#xff0c;然后while循环去根据主键索引的B树结…...

【目标测距】雷达投影测距

文章目录 前言一、读取点云二、点云投影图片三、读取检测信息四、点云投影测距五、学习交流 前言 雷达点云投影相机。图片目标检测&#xff0c;通过检测框约束等等对目标赋予距离。计算消耗较大&#xff0c;适合离线验证操作。在线操作可以只投影雷达检测框。 一、读取点云 py…...

uniapp、小程序canvas相关

1、圆形or圆形头像 //示例 const ctx uni.createCanvasContext(myCanvas); //canvas const round uni.upx2px(72) / 2; // 半径 const x uni.upx2px(92); //目标x轴位置 const y uni.upx2px(236); //目标y轴位置//if 图片是不是静态资源 async > const imgSrc https:/…...

[工业自动化-23]:西门子S7-15xxx编程 - 软件编程 - 西门子PLC人机界面交互HMI功能概述、硬件环境准备、软件环境准备

目录 一、什么是人机界面 二、什么是PLC人机交互界面HMI 三、人机界面设计的功能列表 四、开发主机与PLC的连接方式 五、开发主机与HMI的连接方式 六、HMI组态 一、什么是人机界面 人机界面是指人与机器或系统之间的交互界面。它是人类与计算机或其他设备之间进行信息交换…...

在Ubuntu系统中安装VNC并结合内网穿透实现公网远程访问

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

java基础练习缺少项目?看这篇文章就够了(上)!

公众号&#xff1a;全干开发 。 专注分享简洁但高质量的动图技术文章&#xff01; 项目概述 本教程适合刚学习完java基础语法的同学&#xff0c;涉及if语句、循环语句、类的封装、集合等基础概念&#xff0c;使用大量gif图帮助读者演示代码操作、效果等&#xff0c;是一个非常…...

鸿蒙为什么使用typescript 作为开发语言 而不是 flutter 或者 kotlin

猜想如下 dev studio 是基于 idea 二次开发的 &#xff0c;使用kotlin 应该是更合理 变成 jetbrain 全家桶&#xff0c; 但是 现在android 开发也是kotlin 是不是为了做分割 &#xff0c;所以不使用kotlin flutter 是谷歌的 安卓也是谷歌的 所以不采用 typescript 是微软的…...

Flutter NestedScrollView 、SliverAppBar全解析,悬浮菜单的应用

在我们开发过程中经常会使用到悬浮菜单的使用&#xff0c;当我们滑动到指定位置后&#xff0c;菜单会自动悬浮。 实现效果如下&#xff08;左为滑动前、右为滑动后&#xff09;&#xff1a; 上述便是通过NestedScrollView 、SliverAppBar实现的效果&#xff0c;通过两个控件我…...

Mongodb 副本集名称重命名

副本集重命名 要重命名副本集&#xff0c;您必须关闭副本集的所有成员&#xff0c;然后使用新的副本集名称配置每个成员的数据库。 此过程需要停机。 先决条件 确保您的副本集未分片。重命名过程仅适用于未分片的副本集。 在重命名副本集之前&#xff0c;请 对 MongoDB 部…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...