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

设计模式 创建型 工厂模式(Factory Pattern)与 常见技术框架应用 解析

在这里插入图片描述

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种封装对象创建过程的方式,使得对象的创建与使用分离,从而提高了系统的可扩展性和可维护性。

一、核心思想

工厂模式的核心思想是将“实例化对象”的操作与“使用对象”的操作分开,将实例化对象的责任交给专门的工厂类负责。这样可以降低系统的耦合度,提高系统的可扩展性和可维护性。

二、定义与结构

1、定义

工厂模式稳坐创建型设计模式的头把交椅,其核心使命是匠心独运地架构一种精妙绝伦的机制,使得对象的创建环节与使用环节能够井水不犯河水地分离开来。具体而言,它仰仗一个或多个专业打造的工厂类,依据预设的特定规则、传入的精准参数或者实时监测到的系统条件,英明决断究竟该打造何种类型的对象,并将成品对象精准无误地交付给翘首以盼的代码模块。

2、工厂模式有两种主要形式

2.1、简单工厂模式:不作为设计模式被正式认可,但它是一个常用的概念。它不是严格的设计模式,因为它违反了开闭原则(对扩展开放,对修改关闭)。简单工厂模式包含:

  • 工厂类:负责接收所有创建请求。
  • 产品接口或抽象类:定义产品的公共接口。
  • 具体产品类:实现产品接口的具体产品。

2.2、工厂方法模式:是一种更正式的设计模式,它解决了简单工厂模式的问题,并且遵循开闭原则。它包括:

  • 抽象工厂(Abstract Factory):声明了一个创建产品的接口,其中的工厂方法用于实例化一个产品。通常以抽象类或者接口这般高冷姿态示人,它宛如一位高瞻远瞩的总设计师,定义了一系列用于创建紧密相关的一系列产品对象的抽象方法集。这些抽象方法如同精密模具,为后续衍生出的具体工厂子类勾勒出清晰、统一且规范的创建框架,确保在整个产品家族创建过程中的规范性与一致性得以严格保障。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责实例化具体的产品。作为抽象工厂的忠实拥趸,具体工厂类或是继承自抽象工厂抽象类,或是精准实现其接口。每个具体工厂类都如同一位专注的能工巧匠,与某一种特定类型的产品深度绑定,不离不弃。它负责将抽象工厂中定义的抽象创建方法生动具象化,凭借精湛技艺实实在在地生产出对应的具体产品对象,将抽象的创意构想落地生根。
  • 抽象产品(Abstract Product):定义了产品的接口,具体的产品类将实现这个接口。抽象产品恰似一份精心绘制的蓝图,多以抽象类或接口呈现。它事无巨细地概括了产品所应具备的公共方法、必备属性,为所有跃跃欲试的具体产品类精心规划了前行方向,是判断具体产品是否达标的严苛基准线。
  • 具体产品(Concrete Product):实现了抽象产品接口,是工厂模式所创建的对象。具体产品类则是依据抽象产品所勾勒的蓝图,加班加点精心打造出来的实体杰作。它们或是继承自抽象产品类,或是完美实现其接口,通过夜以继日地实现其中所定义的各种方法,赋予了产品鲜活的生命力,展现出实实在在的功能与特性,以满足千变万化的业务场景需求。

2.3、抽象工厂模式:提供了一组相关或相互依赖的对象的创建接口,而无需指定它们具体的类。这是一种更为复杂的工厂模式,通常用来创建一系列相关的对象。

三、实现步骤及代码示例

以Java为例,展示工厂模式的具体使用。

1、简单工厂模式

// 抽象产品
interface Car {void drive();
}// 具体产品
class BMW implements Car {@Overridepublic void drive() {System.out.println("Driving BMW");}
}class Benz implements Car {@Overridepublic void drive() {System.out.println("Driving Benz");}
}// 工厂类
class CarFactory {public static Car createCar(String type) {if ("BMW".equalsIgnoreCase(type)) {return new BMW();} else if ("Benz".equalsIgnoreCase(type)) {return new Benz();}return null;}
}// 客户端代码
public class Client {public static void main(String[] args) {Car car1 = CarFactory.createCar("BMW");car1.drive();Car car2 = CarFactory.createCar("Benz");car2.drive();}
}

2、工厂方法模式

// 抽象产品
interface Car {void drive();
}// 具体产品
class BMW implements Car {@Overridepublic void drive() {System.out.println("Driving BMW");}
}class Benz implements Car {@Overridepublic void drive() {System.out.println("Driving Benz");}
}// 抽象工厂
interface CarFactory {Car createCar();
}// 具体工厂
class BMWFactory implements CarFactory {@Overridepublic Car createCar() {return new BMW();}
}class BenzFactory implements CarFactory {@Overridepublic Car createCar() {return new Benz();}
}// 客户端代码
public class Client {public static void main(String[] args) {CarFactory bmwFactory = new BMWFactory();Car bmw = bmwFactory.createCar();bmw.drive();CarFactory benzFactory = new BenzFactory();Car benz = benzFactory.createCar();benz.drive();}
}

3、抽象工厂模式

由于抽象工厂模式较为复杂,此处不展开代码示例,但核心思想是提供一个接口,用于创建相关或依赖对象的家族,而不需要指明具体类。

四、常见技术框架应用

1、Spring框架

应用场景:在Spring框架中,工厂模式常用于Bean的创建和管理。Spring容器通过工厂模式来实例化和管理应用程序中的Bean,使得开发者无需手动创建和管理这些对象。

实现方式:Spring容器通过反射机制来调用具体的工厂方法或构造器,创建Bean实例。同时,Spring还支持通过配置文件或注解来指定Bean的创建方式和依赖关系。

2、MyBatis框架

应用场景:MyBatis框架中,SqlSessionFactory是创建SqlSession的工厂类。SqlSession是MyBatis的核心接口,用于执行SQL语句和管理事务。

实现方式:MyBatis通过读取配置文件或注解来构建SqlSessionFactory,然后通过SqlSessionFactory来创建SqlSession实例。这样,开发者无需直接操作数据库连接和SQL语句,提高了代码的可维护性和可扩展性。

3、Java EE/Jakarta EE

应用场景:在Java EE/Jakarta EE中,工厂模式常用于创建和管理企业级应用中的组件和服务。例如,JNDI(Java Naming and Directory Interface)服务通过工厂模式来查找和获取各种资源(如数据库连接、消息队列等)。

实现方式:Java EE/Jakarta EE提供了多种工厂类和接口来支持企业级应用的开发。开发者可以通过这些工厂类和接口来获取所需的服务和资源,而无需关心具体的实现细节。

4、日志框架(如Log4j、SLF4J)

应用场景:日志框架中,工厂模式常用于创建不同类型的日志记录器。根据不同的配置或运行时参数,可以动态地创建和使用不同的日志对象。

实现方式:日志框架通常定义了一个日志接口和多个具体的日志实现类。然后,通过工厂模式来根据配置或参数创建具体的日志记录器实例。这样,开发者可以在不修改代码的情况下灵活地切换日志实现。

5、UI框架(如Swing、JavaFX)

应用场景:在UI框架中,工厂模式常用于创建和管理用户界面组件。通过工厂模式,可以方便地创建和配置各种UI组件,如按钮、文本框、标签等。

实现方式:UI框架通常提供了一组工厂类或方法来创建和管理UI组件。开发者可以通过这些工厂类或方法来创建所需的UI组件,并设置其属性和行为。

以 Spring Boot 框架创建不同数据源连接为例

首先,定义抽象产品:

// 抽象产品:数据源连接
public interface DataSourceConnection {void connect();void close();
}

接着,创建具体产品:

// 具体产品:MySQL 数据源连接
public class MySQLDataSourceConnection implements DataSourceConnection {@Overridepublic void connect() {System.out.println("正在连接 MySQL 数据源...");// 实际连接 MySQL 数据库的代码,此处省略,如加载驱动、配置 URL、用户名、密码等}@Overridepublic void close() {System.out.println("正在关闭 MySQL 数据源连接...");// 关闭连接的代码,此处省略}
}// 具体产品:Oracle 数据源连接
public class OracleDataSourceConnection implements DataSourceConnection {@Overridepublic void connect() {System.out.println("正在连接 Oracle 数据源...");// 实际连接 Oracle 数据库的代码,此处省略,如加载驱动、配置 URL、用户名、密码等}@Overridepublic void close() {System.out.println("正在关闭 Oracle 数据源连接...");// 关闭连接的代码,此处省略}
}

然后,定义抽象工厂:

// 抽象工厂:数据源连接工厂
public abstract class DataSourceConnectionFactory {public abstract DataSourceConnection createConnection();
}

再创建具体工厂:

// 具体工厂:MySQL 数据源连接工厂
public class MySQLDataSourceConnectionFactory extends DataSourceConnectionFactory {@Overridepublic DataSourceConnection createConnection() {return new MySQLDataSourceConnection();}
}// 具体工厂:Oracle 数据源连接工厂
public class OracleDataSourceConnectionFactory extends DataSourceConnectionFactory {@Override
·public DataSourceConnection createConnection() {return new OracleDataSourceConnection();}
}

最后,在 Spring Boot 应用中使用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class DataSourceConfig {@Beanpublic DataSourceConnectionFactory mySQLDataSourceConnectionFactory() {return new MySQLDataSourceConnectionFactory();}@Beanpublic DataSourceConnectionFactory oracleDataSourceConnectionFactory() {return new OracleDataSourceConnectionFactory();}
}

在其他业务代码中,就可以通过 @Autowired 注解注入工厂类,进而获取相应的数据源连接,例如:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class DatabaseService {@Autowiredprivate DataSourceConnectionFactory mySQLDataSourceConnectionFactory;public void doSomething() {DataSourceConnection connection = mySQLDataSourceConnectionFactory.createConnection();connection.connect();connection.close();}
}

以 Hibernate 框架为例

在 Hibernate 中,SessionFactory 可看作是抽象工厂,它负责创建 Session(相当于产品)。

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;public class HibernateExample {public static void main(String[] args) {// 创建 SessionFactory,相当于创建抽象工厂SessionFactory sessionFactory = new Configuration().buildSessionFactory();// 从工厂中获取 Session,相当于使用具体工厂创建产品Session session = sessionFactory.openSession();// 使用 Session 进行数据库操作,此处省略具体代码session.close();sessionFactory.close();}
}

这里,Configuration 类中的一些配置方法和内部逻辑就类似于具体工厂的构建过程,最终构建出 SessionFactory,而 SessionFactory 依据配置信息创建出 Session,用于后续的数据库交互操作。

五、应用场景

  1. 复杂对象创建:当对象创建涉及读取复杂配置文件获取关键初始化参数,像创建数据库连接对象时,要依据配置文件中的数据库 URL、用户名、密码精准配置,还要加载特定的数据库驱动程序,工厂模式便能大显身手,将这些复杂且易错的操作统统封装进工厂类中,使得业务代码只需关注如何使用创建好的对象,彻底与复杂的创建过程绝缘。
  2. 多类型对象按需创建:依据用户输入(如图形编辑软件根据用户所选图形类型创建圆形、矩形、三角形等不同图形)、系统状态(如电商系统根据促销活动创建不同折扣的商品对象)、业务规则(如根据不同的会员等级提供不同服务套餐)等条件,工厂模式通过巧妙设计不同的使具体工厂,能够精准无误地根据各种条件创建出对应的对象,满足多样化的业务需求,实现个性化服务。
  3. 对象创建逻辑频繁变动:在电商促销活动期间,需要根据不同的促销规则频繁创建不同折扣的商品对象;又或是在软件系统迭代升级过程中,需要不断调整对象的创建逻辑以适应新的架构要求。此时,工厂模式的优势就淋漓尽致地展现出来了,它能够在工厂类中方便地修改和扩展对象创建逻辑,而不会对使用这些对象的另业务代码造成任何影响,确保了系统的稳定性与可维护性,让代码在变革中依然保持优雅。

六、优缺点

优点

  1. 解耦对象创建与使用:清晰地划分了对象创建和使用的职责边界,极大地降低了代码之间的耦合度。使得使用对象的代码能够独立于对象的创建过程,便于后续的维护与扩展。当需要对对象创建方式进行调整时,只需在工厂类中进行改动,而不会波及到整个代码库,为代码的长期演进提供了保障。
  2. 提高代码复用性:工厂类具有很强的复用性,尤其是在对象创建过程比较复杂的情况下,复用工厂类能够避免在多个地方重复编写繁琐的创建代码。例如,多个模块都需要创建相同类型的数据库连接对象,此时只需复用同一个数据库连接工厂即可,大大提高了开发效率,减少了代码冗余。
  3. 便于代码的维护和扩展:当需要添加新的产品或者修改产品的创建逻辑时,只需要在所在的工厂类和相应的产品类中进行修改,而不会影响到其他使用这些产品的代码。例如,要在图形绘制系统中添加一种新的品类型,只需要创建新的具体产品类和对应的具体工厂类,而不需要修改图形绘制的主程序,使得系统的可扩展性得到了显著提升,能快速适应业务的变化。

优点

  1. 增加代码复杂性:引入工厂模式必然会增加代码的层次结构和类的数量。对于一些简单的应用场景,如果过度使用工厂模式,反而会使代码变得更加复杂,晦涩难懂,增加了开发人员的理解成本和维护难度。原本简单直接的创建过程可能被层层工厂类包裹,让人迷失在代码的迷宫之中。
  2. 工厂类可能会变得复杂:如果工厂需要创建的产品种类过多,或者产品的创建逻辑非常复杂,工厂类本身可能会变得庞大而复杂,不利于代码的维护。例如,一个工厂类需要根据几十种不同的条件来创建不同类型的对象,此时这个工厂类的代码将会非常冗长,难以理清其中的逻辑关系,给后续的维护工作带来巨大挑战,甚至可能成为代码维护的“黑洞”。

工厂模式凭借其独特的设计理念,为对象创建提供了一种高效、灵活且易于维护的解决方案。尽管存在一定的局限性,但在复杂多变的软件开发场景中,只要合理运用,就能充分发挥其优势,助力打造高质量的软件系统。

在这里插入图片描述

相关文章:

设计模式 创建型 工厂模式(Factory Pattern)与 常见技术框架应用 解析

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种封装对象创建过程的方式,使得对象的创建与使用分离,从而提高了系统的可扩展性和可维护性。 一、核心思想 工厂模式的核心思想是将“实例化对象”的操作与…...

pip 下载安装时使用国内源配置

pip 是 Python 的包管理工具,用于安装和管理第三方库。然而,在某些情况下,默认的 PyPI(Python Package Index)源可能由于网络原因导致下载速度慢或者连接不稳定。幸运的是,我们可以轻松地配置 pip 使用国内…...

【数据结构】数据结构简要介绍

数据结构是计算机科学中用于组织、管理和存储数据的方式,以便于高效地访问和修改数据。 数据结构的分类: 数据结构可以大致分为两类:线性结构和非线性结构。 1. 线性结构 线性结构中的数据按顺序排列,每个元素有唯一的前驱和后…...

数据分析-Excel

数据类型和函数初步 Excel中有文本类型和数值类型–但是无法用肉眼分辨出来isnumber来区分是否是数值类型text和value函数可以完成数值类型以及文本类型的转换单元格第一位输入’方式明确输入的是文本sum函数必须是数值类型 文本连接-and-or-not-if-mod-max函数 字符串的连接…...

Yocto项目—机器配置文件详解

引言 在Yocto项目中,机器配置文件(Machine Configuration File)是系统定制化的重要组成部分,直接决定了构建的目标平台硬件特性和能力。本文将深入探讨Yocto项目中的机器配置文件,从其作用、结构到具体配置方法&#…...

30天开发操作系统 第 10 天 -- 叠加处理

前言 得益于昨天的努力,我们终于可以进行内存管理了。不过仔细一看会注意到,bootpack.c都已经有254行了。笔者感觉这段程序太长了,决定整理一下,分出一部分到memory.c中去。(整理中)…好了,整理完了。现在bootpack.c变…...

第十讲 比特币的社会与文化影响

比特币作为一种革命性的数字货币,不仅在经济领域产生了深远的影响,也在社会和文化层面引发了广泛的讨论和变革。本文将探讨比特币如何塑造我们的社会观念、文化趋势以及对未来的展望。 一、比特币与社会观念的变迁 比特币的出现挑战了传统的货币观念和…...

Unity2D无限地图的实现(简单好抄)

说明:本教程实现的是在2D游戏中玩家在游戏中上下左右移动的时候自动进行地图拼接的功能,如果你只想实现左右移动的无限地图,那么这篇博客也能起到一定参考作用。 思路 第一步: 创建一个10*10的2D游戏对象当做地图 第二步创建一个…...

TCP网络编程(一)—— 服务器端模式和客户端模式

这篇文章将会编写基本的服务器网络程序,主要讲解服务器端和客户端代码的原理,至于网络名词很具体的概念,例如什么是TCP协议,不会过多涉及。 首先介绍一下TCP网络编程的两种模式:服务器端和客户端模式: 首先…...

03-类和对象(上)

一、类的概述 1.类的引入 类的封装:将数据和方法封装在一起,加以权限区分,用户只能通过公共方法访问私有数据。 为什么要将数据和方法封装在一起呢,而且还要通过公共方法才能访问私有数据? C语言中数据和方法分开可…...

PCL点云库入门——PCL库点云滤波算法之统计滤波(StatisticalOutlierRemoval)

1、算法原理 统计滤波算法是一种利用统计学原理对点云数据进行处理的方法。它主要通过计算点云中每个点的统计特性,如均值、方差等,来决定是否保留该点。算法首先会设定一个统计阈值,然后对点云中的每个点进行分析。如果一个点的统计特性与周…...

【机器学习】Kaggle实战信用卡反欺诈预测(场景解析、数据预处理、特征工程、模型训练、模型评估与优化)

构建信用卡反欺诈预测模型 建模思路 本项目需解决的问题 本项目通过利用信用卡的历史交易数据,进行机器学习,构建信用卡反欺诈预测模型,提前发现客户信用卡被盗刷的事件。 项目背景 数据集包含由欧洲持卡人于2013年9月使用信用卡进行交的…...

【RISC-V CPU debug 专栏 4 -- RV CSR寄存器介绍】

文章目录 Overview1. CSR寄存器访问指令2. 为何CSR地址不是4字节对齐(1) CSR寄存器空间是独立的地址空间(2) 节省编码空间(3) 对硬件实现的简化 3. CSR的物理大小和对齐无关4. RISC-V 中的 GPR 寄存器及其作用GPR 的详细用途CSR(控制状态寄存器)与 GPR 的…...

Object.defineProperty() 完整指南

Object.defineProperty() 完整指南 1. 基本概念 Object.defineProperty() 方法允许精确地添加或修改对象的属性。默认情况下,使用此方法添加的属性是不可修改的。 1.1 基本语法 Object.defineProperty(obj, prop, descriptor)参数说明: obj: 要定义…...

postgresql函数创建

postgresql的函数创建 1.创建函数的基本语法: CREATE [OR REPLACE] FUNCTION function_name(parameter_list) RETURNS return_type AS $$ BEGIN -- 函数体 END; $$ LANGUAGE language_name;2.创建函数时传入参数示例:add_user tbl_user表 | id | username | …...

ECMAScript 变量

文章目录 前言一、ECMAScript 变量二、var 关键字1、var 声明作用域2、var 声明提升(hoist)三、let 关键字四、const 关键字🔰 总结前言 任何语言的核心所描述的都是这门语言在最基本的层面上如何工作,涉及 语法、操作符、数据类型以及内置功能,在此基础之上才可以构建复…...

CAN总线波形中最后一位电平偏高或ACK电平偏高问题分析

参考:https://zhuanlan.zhihu.com/p/689336144 有时候看到CAN总线H和L的差值波形的最后一位电平会变高很多,这是什么原因呢? 实际上这是正常的现象,最后一位是ACK位。问题描述为:CAN总线ACK电平偏高。 下面分析下原因…...

【C++】22___STL常用算法

目录 一、常用遍历算法 二、常用查找算法 2.1 find 2.2 其它查找算法 三、常用排序算法 3.1 sort 3.2 其它排序算法 四、拷贝 & 替换 4.1 copy 4.2 其它算法 五、常用的算数生成算法 5.1 accumulate 5.2 fill 六、常用集合算法 6.1 set_intersection 6…...

意静明和-十成

十成 责任(健康)、使命(事业)、信念(意义)、自律(排诱)、自修(知识)、总结(四为)、执行(一事不拖)、人情&…...

easyui textbox使用placeholder无效

easyui textbox使用placeholder无效 在easyui 的textbox控件&#xff0c;请使用data-options 设定 示例 <input type text class easyui-textbox data-options "prompt:请输入您的邮箱"/>...

flux中的缓存

1. cache&#xff0c;onBackpressureBuffer。都是缓存。cache可以将hot流的数据缓存起来。onBackpressureBuffer也是缓存&#xff0c;但是当下游消费者的处理速度比上游生产者慢时&#xff0c;上游生产的数据会被暂时存储在缓冲区中&#xff0c;防止丢失。 2. Flux.range 默认…...

代码重定位详解

文章目录 一、段的概念以及重定位的引入1.1 问题的引入1.2 段的概念1.3 重定位 二、如何实现重定位2.1 程序中含有什么&#xff1f;2.2 谁来做重定位&#xff1f;2.3 怎么做重定位和清除BSS段&#xff1f;2.4 加载地址和链接地址的区别 三、散列文件使用与分析3.1 重定位的实质…...

活动预告 | Microsoft 365 在线技术公开课:让组织针对 Microsoft Copilot 做好准备

课程介绍 通过Microsoft Learn免费参加Microsoft 365在线技术公开课&#xff0c;建立您需要的技能&#xff0c;以创造新的机会并加速您对Microsoft云技术的理解。参加我们举办的“让组织针对 Microsoft Copilot for Microsoft 365 做好准备” 在线技术公开课活动&#xff0c;学…...

从0到机器视觉工程师(一):机器视觉工业相机总结

目录 相机的作用 工业相机 工业相机的优点 工业相机的种类 工业相机知名品牌 光源与打光 打光方式 亮暗场照明 亮暗场照明的应用 亮暗场照明的区别 前向光漫射照明 背光照明 背光照明的原理 背光照明的应用 同轴光照明 同轴光照明的应用 总结 相机的作用 相机…...

Docker安装(Docker Engine安装)

一、Docker Engine和Desktop区别 Docker Engine 核心组件&#xff1a;Docker Engine是Docker的核心运行时引擎&#xff0c;负责构建、运行和管理容器。它包括守护进程&#xff08;dockerd&#xff09;、API和命令行工具客户端&#xff08;docker&#xff09;。适用环境&#…...

数组的深度监听deep

场景&#xff1a;组件提供的emit事件可能被占用&#xff0c;在不能使用事件提交的情况下&#xff0c;就要上watch数组监听了&#xff0c;但是是发现只有在数组的长度发生变化的时候才会触发监听&#xff0c;这怎么行。。。。。 对于对象数组的深度监听&#xff0c;如果没有正确…...

点击锁定按钮,锁定按钮要变成解锁按钮,然后状态要从待绑定变成 已锁定(升级版)

文章目录 1、updateInviteCodeStatus2、handleLock3、InviteCodeController4、InviteCodeService5、CrudRepository 点击锁定按钮&#xff0c;锁定按钮要变成解锁按钮&#xff0c;然后状态要从待绑定变成 已锁定&#xff1a;https://blog.csdn.net/m0_65152767/article/details…...

UniApp 性能优化策略

一、引言 在当今数字化时代&#xff0c;移动应用的性能成为影响用户留存与满意度的关键因素。UniApp 作为一款热门的跨平台开发框架&#xff0c;以一套代码适配多端的特性极大提升了开发效率&#xff0c;但同时也面临着性能优化的挑战。优化 UniApp 性能&#xff0c;不仅能够让…...

【Linux报告】实训六 重置超级用户密码

实训六 重置超级用户密码 2018编写-今日公布 【练习一】忘记root密码 步骤一&#xff1a;开启或重启系统&#xff0c;并且要在五秒之内按任何键&#xff1b; 步骤二&#xff1a;按任意键&#xff0c;停止进入系统&#xff0c;按【e】键&#xff0c;跳转新页面&#xff0c;再…...

smolagents:一个用于构建代理的简单库

HF推出 smolagents&#xff0c;一个非常简单的库&#xff0c;它能够解锁语言模型的代理功能。以下是它的简要介绍&#xff1a; from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModelagent CodeAgent(tools[DuckDuckGoSearchTool()], modelHfApiModel())agent…...