Laravel DDD架构实践:使用Neuron Core构建可维护业务系统

news2026/5/16 9:56:25
1. 项目概述一个为Laravel打造的现代化神经元网络核心如果你正在用Laravel构建一个中大型应用并且已经受够了在控制器里塞满几百行业务逻辑或者在模型里写满各种scope和accessor让它们变得臃肿不堪那么neuron-core/neuron-laravel这个项目可能会让你眼前一亮。这不是一个教你如何写CRUD的包而是一个旨在为Laravel应用引入清晰、可维护的领域驱动设计架构的“脚手架”或“架构核心”。简单来说它试图在Laravel这个优秀的全栈框架之上建立一套更严谨的代码组织规范把业务逻辑从框架的“胶水层”中解放出来让它们住进自己该住的“房子”里。我自己在经历了好几个从快速原型演变成“祖传代码”的Laravel项目后开始迫切地寻找一种能提升代码长期可维护性的方法。DDD是一个理想但直接在Laravel里实践总会遇到各种“水土不服”目录结构怎么摆领域事件怎么发仓储模式怎么和Eloquent优雅结合neuron-laravel的出现可以看作是一个社区给出的、经过实践打磨的参考答案。它不是一个颠覆性的框架而是一套建立在Laravel坚实基底上的“内功心法”帮你把应用的核心——业务逻辑——梳理得井井有条。2. 核心架构与设计理念拆解2.1 为什么是“神经元”理解其架构隐喻项目命名为“Neuron”即神经元这是一个非常贴切的隐喻。在一个复杂系统中神经元是独立处理信号的基本单元它们通过突触连接形成网络最终产生智能行为。映射到软件架构中每个“神经元”代表一个高内聚的领域对象或业务逻辑单元比如一个User实体、一个CreateOrder命令、或者一个PaymentProcessed事件。“突触连接”则代表了这些单元之间定义良好的交互方式比如通过领域事件发布/订阅、通过命令总线分发、或者通过定义清晰的接口进行依赖注入。整个“神经网络”就是你的应用程序其智能业务价值来源于这些规范、清晰的单元协作而非一堆混杂在控制器里的面条式代码。neuron-laravel的核心设计理念就是帮助开发者构建这样一个由“神经元”组成的清晰网络。它推崇领域驱动设计与命令查询职责分离的结合。DDD负责界定业务边界和核心概念CQRS则负责将修改状态的操作和查询数据的操作在架构上分离两者结合能极大地提升复杂业务系统的可理解性和可扩展性。2.2 核心组件与职责边界这套架构通常包含以下几个关键组件neuron-laravel为它们提供了实现的基类、约定和工具实体与值对象这是领域模型的核心。实体具有唯一标识和生命周期如Order值对象描述属性无标识如Money。neuron-laravel鼓励你使用纯PHP类来定义它们与数据库实现解耦。聚合与聚合根聚合是一组相关对象的集合作为一个整体被修改和持久化聚合根是入口点。例如Order聚合根可能包含OrderItem值对象列表。这明确了数据一致性的边界。仓储仓储是领域层和数据持久化层之间的抽象。它提供类似集合的接口来存取聚合根隐藏了底层是使用Eloquent、Redis还是其他机制的具体细节。neuron-laravel通常会提供基础的仓储接口和与Eloquent集成的便捷实现。命令与命令处理器命令是一个描述用户意图的DTO如RegisterUserCommand。命令处理器是执行该意图的无状态服务包含核心业务逻辑。这使每个业务操作都变得明确、可测试。领域事件与事件监听器当领域内发生重要事情时如UserRegistered会发布一个领域事件。其他部分可以订阅这些事件来触发后续操作如发送欢迎邮件、初始化用户资料。这实现了业务组件之间的松耦合通信。查询与查询处理器与命令类似查询对象描述要获取的数据查询处理器专门负责优化数据查询并返回DTO。这使复杂的读取逻辑得以集中和优化不受写入模型的影响。注意引入这套架构会显著增加项目前期的复杂度和文件数量。它非常适合业务逻辑复杂、长期演进、团队协作的中大型项目。对于简单的CRUD应用或一次性原型这可能属于过度设计。3. 项目初始化与基础结构搭建3.1 安装与基础配置首先通过Composer将neuron-laravel引入你的项目。通常它作为一个开发时的架构引导包存在。composer require neuron-core/neuron-laravel --dev安装后项目可能会提供一个Artisan命令来发布其提供的骨架文件和配置。这是关键一步因为它会在你的app目录下创建符合DDD和CQRS约定的子目录结构。php artisan vendor:publish --providerNeuron\\Laravel\\NeuronServiceProvider --tagneuron-stubs执行后你的app目录可能会变成这样或类似app/ ├── Domains/ │ ├── User/ │ │ ├── Commands/ │ │ ├── Entities/ │ │ ├── Events/ │ │ ├── Listeners/ │ │ ├── Queries/ │ │ └── Repositories/ │ └── Order/ │ ├── Commands/ │ ├── Entities/ │ ├── ... ├── Support/ │ ├── Bus/ │ ├── Exceptions/ │ └── ...这个结构将代码按领域而非技术职责进行组织。所有关于“用户”的业务逻辑无论命令、查询还是事件都集中在Domains/User下。这极大地提升了代码的可发现性和可维护性。3.2 第一个领域模块创建实战假设我们要构建一个“用户注册”功能。传统Laravel方式可能直接在控制器里调用User::create。现在我们用neuron-laravel的思维来操作。首先使用包提供的生成器命令创建领域模块。这能确保文件被放在正确的位置并继承正确的基类。php artisan neuron:domain User这个命令可能会在app/Domains/User下创建好基础的目录结构。接下来我们生成一个注册命令及其处理器php artisan neuron:command RegisterUser --domainUser这个命令可能会生成两个文件app/Domains/User/Commands/RegisterUserCommand.php一个数据对象包含注册所需的数据邮箱、密码等。app/Domains/User/Commands/RegisterUserHandler.php一个处理器类包含实际的注册逻辑。让我们看看RegisterUserCommand可能的样子?php namespace App\Domains\User\Commands; use Neuron\Laravel\Core\Command; class RegisterUserCommand extends Command { public string $email; public string $password; public string $name; public function __construct(string $email, string $password, string $name) { $this-email $email; $this-password $password; $this-name $name; } }它非常简单只是一个数据的容器负责从外部如HTTP请求接收数据并传递给处理器。真正的业务逻辑在RegisterUserHandler中?php namespace App\Domains\User\Commands; use App\Domains\User\Entities\User; use App\Domains\User\Events\UserRegistered; use App\Domains\User\Repositories\UserRepositoryInterface; use Illuminate\Support\Facades\Hash; class RegisterUserHandler { public function __construct(private UserRepositoryInterface $users) {} public function handle(RegisterUserCommand $command): User { // 1. 业务规则校验例如检查邮箱唯一性这里假设仓储会处理 // 2. 创建领域实体 $user new User( email: $command-email, passwordHash: Hash::make($command-password), name: $command-name ); // 3. 通过仓储持久化实体 $this-users-save($user); // 4. 发布领域事件通知系统其他部分 event(new UserRegistered($user)); return $user; } }注意处理器不关心数据从哪里来HTTPCLI队列也不关心数据存到哪里MySQLPostgreSQL。它只专注于业务规则。密码哈希是一个技术细节但它直接关系到安全这个业务规则所以放在这里是合适的。持久化被委托给仓储事件发布使用Laravel内置的event辅助函数但事件本身是领域事件。4. 核心领域模型与数据持久化实现4.1 定义富领域实体在DDD中实体不是简单的“贫血模型”。它应该封装数据和与之相关的行为。让我们定义User实体。php artisan neuron:entity User --domainUser生成的实体基类可能引导我们这样编写?php namespace App\Domains\User\Entities; use Neuron\Laravel\Core\Entity; use Illuminate\Support\Facades\Hash; class User extends Entity { private string $id; private string $email; private string $passwordHash; // 注意我们存储的是哈希值 private string $name; private ?string $emailVerifiedAt null; public function __construct(string $id, string $email, string $passwordHash, string $name) { $this-id $id; $this-email $email; $this-passwordHash $passwordHash; $this-name $name; } // 身份标识访问器 public function getId(): string { return $this-id; } public function getEmail(): string { return $this-email; } public function getName(): string { return $this-name; } // 业务行为方法 public function verifyPassword(string $plainPassword): bool { return Hash::check($plainPassword, $this-passwordHash); } public function markEmailAsVerified(): void { $this-emailVerifiedAt now()-toDateTimeString(); } public function isEmailVerified(): bool { return !is_null($this-emailVerifiedAt); } // 可能用于序列化到持久层 public function toArray(): array { return [ id $this-id, email $this-email, password $this-passwordHash, // 数据库字段可能就叫password name $this-name, email_verified_at $this-emailVerifiedAt, ]; } }这个User实体有几个关键点1) 属性是private的状态只能通过公共方法改变保证了不变性。2) 包含了业务行为如verifyPassword而不是将密码验证逻辑散落在各处。3) 它完全不知道Eloquent的存在是一个纯粹的领域对象。4.2 实现仓储模式与Eloquent集成领域层定义了UserRepositoryInterface但实现细节在基础设施层。neuron-laravel通常会提供一个基于Eloquent的便捷仓储实现。首先定义接口在领域层// app/Domains/User/Repositories/UserRepositoryInterface.php namespace App\Domains\User\Repositories; use App\Domains\User\Entities\User; interface UserRepositoryInterface { public function save(User $user): void; public function findById(string $id): ?User; public function findByEmail(string $email): ?User; public function delete(string $id): bool; }然后在基础设施层可能是app/Infrastructure或直接使用Laravel的模型实现它。neuron-laravel可能提供了一个抽象的EloquentRepository// app/Infrastructure/Repositories/EloquentUserRepository.php namespace App\Infrastructure\Repositories; use App\Domains\User\Entities\User; use App\Domains\User\Repositories\UserRepositoryInterface; use App\Models\User as UserModel; // 这是Eloquent模型 use Neuron\Laravel\Support\Repositories\EloquentRepository; class EloquentUserRepository extends EloquentRepository implements UserRepositoryInterface { protected string $entityClass User::class; protected string $modelClass UserModel::class; public function save(User $user): void { $data $user-toArray(); // 如果ID存在则更新否则创建 $this-modelClass::updateOrCreate([id $data[id]], $data); } public function findById(string $id): ?User { $model $this-modelClass::find($id); return $model ? $this-toEntity($model) : null; } public function findByEmail(string $email): ?User { $model $this-modelClass::where(email, $email)-first(); return $model ? $this-toEntity($model) : null; } // toEntity 方法负责将Eloquent模型转换为领域实体 protected function toEntity($model): User { return new User( id: $model-id, email: $model-email, passwordHash: $model-password, // 假设数据库字段是password name: $model-name, // ... 其他属性 ); } }最后在Laravel的服务容器中绑定接口到具体实现// app/Providers/AppServiceProvider.php public function register() { $this-app-bind( \App\Domains\User\Repositories\UserRepositoryInterface::class, \App\Infrastructure\Repositories\EloquentUserRepository::class ); }这样在命令处理器中我们通过构造函数注入的永远是UserRepositoryInterface实现了领域层与基础设施层的解耦。未来如果要把用户数据存到MongoDB只需新建一个MongoUserRepository并修改绑定即可领域逻辑完全不用动。5. 命令、查询与事件总线的协同工作流5.1 命令总线的分发与执行在neuron-laravel的架构下控制器会变得非常“薄”。它的职责仅仅是接收HTTP请求将其转换为命令对象然后交给命令总线去执行。首先我们需要一个能分发命令的总线。Laravel的队列和任务系统本身就是一个很棒的命令总线neuron-laravel可能会对其进行封装使其更易于处理同步命令。在控制器中// app/Http/Controllers/Api/Auth/RegisterController.php namespace App\Http\Controllers\Api\Auth; use App\Domains\User\Commands\RegisterUserCommand; use App\Http\Controllers\Controller; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Neuron\Laravel\Support\Bus\DispatchesCommands; class RegisterController extends Controller { use DispatchesCommands; // 使用包提供的命令分发trait public function __invoke(Request $request): JsonResponse { $request-validate([ email required|email|unique:users,email, password required|min:8|confirmed, name required|string|max:255, ]); // 创建命令对象 $command new RegisterUserCommand( email: $request-input(email), password: $request-input(password), name: $request-input(name) ); // 通过命令总线同步执行并获取返回的User实体 $user $this-dispatchCommand($command); return response()-json([ message User registered successfully., user [ id $user-getId(), email $user-getEmail(), name $user-getName(), ] ], 201); } }DispatchesCommands这个trait背后的dispatchCommand方法其核心可能就是调用Laravel容器来自动解析并执行对应的命令处理器。它确保了命令和处理器之间的一一映射关系通常通过命名约定RegisterUserCommand-RegisterUserHandler或手动注册来实现。5.2 领域事件的发布与异步处理当UserRegistered事件在命令处理器中被发布后我们可以监听它来执行一些副作用比如发送欢迎邮件。这些监听器不应该包含核心业务逻辑而是响应领域事件。首先创建事件和监听器php artisan neuron:event UserRegistered --domainUser php artisan neuron:listener SendWelcomeEmail --eventUserRegistered事件类UserRegistered很简单就是一个携带了$user实体的DTOnamespace App\Domains\User\Events; use App\Domains\User\Entities\User; class UserRegistered { public function __construct(public User $user) {} }监听器SendWelcomeEmailnamespace App\Domains\User\Listeners; use App\Domains\User\Events\UserRegistered; use App\Mail\WelcomeEmail; use Illuminate\Support\Facades\Mail; class SendWelcomeEmail { public function handle(UserRegistered $event): void { // 这里可以加入判断比如只有验证了邮箱才发送 // 但通常欢迎邮件在注册后立即发送。 Mail::to($event-user-getEmail()) -send(new WelcomeEmail($event-user)); } }接下来我们需要注册这个事件监听。neuron-laravel可能会提供一个专门的地方来注册领域事件或者鼓励你使用Laravel自带的EventServiceProvider。// app/Providers/EventServiceProvider.php protected $listen [ \App\Domains\User\Events\UserRegistered::class [ \App\Domains\User\Listeners\SendWelcomeEmail::class, ], ];实操心得领域事件是解耦业务逻辑的利器。但要注意事件处理应该是“尽力而为”的并且不能影响主业务流程的完整性。例如发送邮件失败不应导致用户注册失败。因此经常会将事件监听器放入队列异步执行。在Laravel中只需让监听器实现ShouldQueue接口即可。5.3 查询模型的优化实践对于复杂的读取场景比如一个用户仪表盘需要聚合来自用户、订单、评论等多个聚合的数据直接使用领域实体和仓储可能会效率低下并且让查询逻辑侵入领域层。这时CQRS中的“查询端”就派上用场了。我们可以创建专门的查询对象和处理器甚至使用独立的、为查询优化的数据库模型。php artisan neuron:query GetUserDashboard --domainUser查询对象GetUserDashboardQuerynamespace App\Domains\User\Queries; class GetUserDashboardQuery { public function __construct(public string $userId) {} }查询处理器GetUserDashboardHandlernamespace App\Domains\User\Queries; use App\Domains\User\DataTransferObjects\UserDashboardData; use Illuminate\Support\Facades\DB; class GetUserDashboardHandler { public function handle(GetUserDashboardQuery $query): UserDashboardData { // 使用原生SQL或查询构造器进行高效的联表查询 $data DB::table(users as u) -leftJoin(orders as o, u.id, , o.user_id) -leftJoin(reviews as r, u.id, , r.user_id) -where(u.id, $query-userId) -select( u.name, u.email, DB::raw(COUNT(DISTINCT o.id) as order_count), DB::raw(AVG(r.rating) as avg_rating) ) -groupBy(u.id, u.name, u.email) -first(); // 返回一个专门为视图优化的DTO而不是领域实体 return new UserDashboardData( userName: $data-name, userEmail: $data-email, totalOrders: $data-order_count, averageRating: (float) $data-avg_rating ); } }对应的DTOUserDashboardData就是一个简单的数据容器。在控制器中我们分发查询并直接返回这个DTO给前端。这种方式将复杂的查询逻辑隔离在专门的处理器中它们可以自由地使用任何优化手段如数据库视图、读写分离从库而不会污染领域模型。6. 测试策略与项目维护要点6.1 分层测试策略采用这种架构后测试也变得更有层次和针对性。领域实体/值对象单元测试测试实体自身的业务规则和行为。这部分测试不依赖任何框架速度快。// tests/Unit/Domains/User/Entities/UserTest.php public function test_it_can_verify_correct_password() { $user new User(id1, testmail.com, Hash::make(secret), John); $this-assertTrue($user-verifyPassword(secret)); $this-assertFalse($user-verifyPassword(wrong)); }命令/查询处理器单元测试模拟仓储等依赖测试处理器的业务逻辑流。// tests/Unit/Domains/User/Commands/RegisterUserHandlerTest.php public function test_it_creates_and_saves_user() { $userRepo Mockery::mock(UserRepositoryInterface::class); $userRepo-shouldReceive(save)-once(); // 期望保存被调用一次 $handler new RegisterUserHandler($userRepo); $command new RegisterUserCommand(testmail.com, secret, John); // 这里我们无法断言返回的User对象内部状态因为它是新创建的。 // 但我们可以断言它被保存了。 $this-expectsEvents(UserRegistered::class); // Laravel提供的测试辅助函数 $handler-handle($command); }集成测试测试仓储的实际实现如与数据库的交互、命令总线的分发、事件监听器的触发等。// tests/Feature/Api/Auth/RegistrationTest.php public function test_user_can_register() { $response $this-postJson(/api/register, [ email testexample.com, password password123, password_confirmation password123, name Test User, ]); $response-assertStatus(201); $this-assertDatabaseHas(users, [email testexample.com]); // 可以进一步断言邮件队列中有任务等 }6.2 常见问题与排查技巧实录在实践neuron-laravel这类架构时会遇到一些典型问题。问题1依赖注入失败提示“Target [Interface] is not instantiable”。排查这几乎总是因为接口没有在服务容器中绑定到具体实现。检查你的AppServiceProvider或相关领域服务提供者中的register方法。解决确保每个领域层的接口都在基础设施层有对应的实现并且绑定了。neuron-laravel有时会提供自动发现和绑定的机制需要检查其文档。问题2命令处理器没有被自动调用。排查检查命令和处理器是否遵循了命名约定如XxxCommand对应XxxHandler。查看包的BusServiceProvider或类似的服务提供者看它如何注册命令到处理器的映射。有时需要手动注册。解决如果包支持在app/neuron.php或类似配置文件中手动注册映射RegisterUserCommand RegisterUserHandler。问题3领域事件监听器没有触发。排查首先确认事件是否被正确发布event()辅助函数或依赖注入的Dispatcher。然后检查EventServiceProvider中的$listen数组是否正确定义。如果监听器是队列化的检查队列驱动是否正常工作。解决使用Log在事件构造函数和监听器handle方法中打日志是最直接的调试方式。确保监听器没有抛出未处理的异常。问题4感觉项目文件数量爆炸式增长简单功能也变得繁琐。这是架构选择的代价而非问题。评估问自己这个项目的业务逻辑真的复杂到需要如此精细的分离吗它是一个长期维护、多人协作的核心业务系统还是一个生命周期短的简单工具建议不要教条主义。对于确实简单的CRUD模块可以适度简化例如直接使用Eloquent模型作为“聚合根”或者在一个处理器里处理多个紧密相关的操作。架构是工具服务于项目和团队而不是相反。问题5事务管理应该放在哪一层最佳实践事务的边界通常与一个“用例”或“应用服务”对应。在neuron-laravel架构中命令处理器通常被定义为一个事务边界。因为一个命令代表一个明确的用户意图要么完全成功要么完全失败。实现可以在命令处理器的方法上使用Laravel的transactional注解或者在命令总线分发器层面包裹一个数据库事务。确保仓储操作都在同一个事务内。use Illuminate\Support\Facades\DB; class RegisterUserHandler { public function handle(RegisterUserCommand $command): User { return DB::transaction(function () use ($command) { // ... 业务逻辑和仓储操作 }); } }7. 进阶模块化与界限上下文的初步探索当项目规模进一步扩大单个Domains目录可能变得臃肿。这时可以考虑向模块化或界限上下文演进。neuron-laravel可能为更高级的模块化提供了支持或者你可以借助Laravel的包自动发现功能将每个领域或界限上下文组织成一个独立的Composer包。例如你可以创建一个user-domain包其src目录结构就和之前的app/Domains/User类似。这个包定义了自己的实体、命令、事件和仓储接口。然后在主应用中安装这个包并提供一个基础设施实现如EloquentUserRepository并完成绑定。这种方式带来了更高的解耦和复用性但同时也大幅增加了构建和部署的复杂度。它适用于大型产品线或微服务架构的早期形态。对于大多数应用将领域组织在app/Domains目录下已经足够清晰和有效。我个人在引入这类架构后的最大体会是它迫使你在写代码前先思考业务。创建命令、实体、事件的过程就是在对业务需求进行建模。虽然前期投入更多但在应对需求变更、新人加入理解代码、以及进行单元测试时其带来的长期收益是巨大的。它像是一份活的、可执行的业务文档。当然最关键的是要与团队达成共识并保持一定的纪律性避免架构在匆忙中腐化。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…