10、DDD分层架构

        微服务架构模型有很多种,例如洋葱架构、CQRS和六边形架构等。虽然这些架构模式提出的时代和背景不同,但其核心理念都是为了设计出“高内聚,低耦合”的微服务,轻松实现微服务的架构演进。DDD分层架构的出现,使微服务的架构边界变得越来越清晰,在微服务架构模型中,占有非常重要的位置。那DDD分层架构到底是什么样?DDD分层架构如何推动架构演进?我们该怎么转向DDD分层架构?本章将重点解决这些问题 。

1、什么是DDD分层架构

DDD分层架构其实也在不断发展和演进。早期的DDD分层架构是一种各层都依赖于基础层的传统四层架构,后来这种四层架构进一步优化,实现了各层对基础层的解耦和依赖倒置。

在最早的传统四层架构中,基础层被其他层依赖,位于最核心的位置,是其他各层依赖的核心。但实际上领域层才是软件的核心,所以这种依赖关系是有问题的。后来就采用了依赖倒置设计,各层服务通过仓储接口访问基础层,从而优化了传统的DDD四层架构,实现了DDD各层对基础层的解耦 。

我们本章要重点讲解的就是优化后的DDD分层架构。DDD分层架构中包含四层,从上到下依次是:用户接口层、应用层、领域层和基础层

1.1 用户接口层

在很多描述DDD用户接口层的文章中,对用户接口层的解释通常都是这样的:“用户接口层负责向用户显示信息和解释用户指令,这里的用户可能是用户、程序、自动化测试和批处理脚本等。”但随着微服务架构的盛行,大多数应用都采用了前后端分离的设计模式。为了连接前端应用和后端微服务,于是又出现了API网关 。

结合洋葱模型和端口适配器架构模型,我在这里稍微拓展一下用户接口层的作用。在微服务面向不同前端应用时,同样的一段业务逻辑,可能由于渠道不同,而在前端展示的页面要素不同,因此要求后端微服务返回的数据结果会不同。例如在面向内部员工的PC端应用时,可能要求返回某些对象的全部属性的数据,而在面向外部客户的移动端应用时,可能只需要返回几个关键属性的数据就可以了。

为了避免暴露微服务的核心业务逻辑,防止数据外泄,不能将后端数据直接暴露给前端应用。为此,可以在用户接口层引入数据传输对象(DTO)和门面接口(Facade Interface),通过这些适配器来提供灵活的数据接口,满足不同前端应用的需求 。

1.2 应用层

应用层主要负责服务的组合和编排,实现业务逻辑。应用服务通过调用领域层的功能来处理用户请求,并将处理结果返回给用户。应用层的设计需要关注以下几个方面:

  • 服务编排:根据业务需求,调用多个领域服务,实现业务功能。
  • 事务管理:管理业务操作的事务,确保数据一致性。
  • 安全控制:处理用户权限和身份验证,确保只有合法用户可以执行操作 。

应用层通常通过应用服务(Application Services)来实现。应用服务是应用层的核心组件,负责处理具体的业务操作。例如,订单服务的实现可能如下:

public class OrderApplicationService {private final OrderRepository orderRepository;private final PaymentService paymentService;public OrderApplicationService(OrderRepository orderRepository, PaymentService paymentService) {this.orderRepository = orderRepository;this.paymentService = paymentService;}public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);paymentService.processPayment(order.getPaymentDetails());}public OrderDTO getOrder(String orderId) {Order order = orderRepository.findById(orderId);return new OrderDTO(order);}
}
1.3 领域层

领域层是DDD分层架构的核心,负责处理系统的业务逻辑。领域层包含领域模型和领域服务,通过对领域对象和领域行为的建模,实现业务需求 。

领域层的组成

领域层通常包含以下组件:

  • 实体(Entity):具有唯一标识符的对象,表示业务中的关键概念。
  • 值对象(Value Object):无唯一标识符的对象,表示业务中的描述性概念。
  • 聚合(Aggregate):一组相关对象的集合,以聚合根(Aggregate Root)为唯一入口。
  • 领域服务(Domain Service):处理跨实体的业务逻辑。
  • 仓储(Repository):负责实体的持久化和检索 。
领域层的职责
  • 建模业务逻辑:通过实体、值对象和聚合等模型来表示业务逻辑。
  • 执行业务操作:通过领域服务执行复杂的业务操作。
  • 维护数据一致性:确保领域模型的状态在业务操作后保持一致 。

领域层的实现需要结合具体的业务需求进行设计。以下是一个简单的领域层实现示例:

public class Order {private OrderId id;private List<OrderItem> items;private OrderStatus status;public Order(OrderId id, List<OrderItem> items) {this.id = id;this.items = items;this.status = OrderStatus.CREATED;}public void addItem(OrderItem item) {items.add(item);}public void removeItem(OrderItem item) {items.remove(item);}public void place() {if (items.isEmpty()) {throw new IllegalStateException("Cannot place an order with no items.");}this.status = OrderStatus.PLACED;}// getters and other methods
}
1.4 基础层

基础层提供系统运行所需的技术支持和基础服务。基础层的设计需要考虑系统的性能、可靠性和可扩展性。

基础层的职责
  • 数据持久化:负责将领域对象持久化到数据库中。
  • 消息传递:处理系统内外部的消息传递,如事件总线、消息队列等。
  • 第三方集成:与外部系统或服务集成,如支付网关、邮件服务等 。

基础层的实现通常涉及数据库访问、消息中间件、外部服务调用等。以下是一个基础设施层的简单实现示例:

public class JpaOrderRepository implements OrderRepository {private final EntityManager entityManager;public JpaOrderRepository(EntityManager entityManager) {this.entityManager = entityManager;}@Overridepublic void save(Order order) {entityManager.persist(order);}@Overridepublic Order findById(OrderId id) {return entityManager.find(Order.class, id);}
}
1.5 DDD分层架构的重要原则

DDD分层架构有一个重要的依赖原则:“每层只能与位于其下方的层发生耦合”。根据耦合的紧密程度,可以分为两种架构模式:严格分层架构和松散分层架构 。

严格分层架构

严格分层架构要求每一层只能依赖于其下层的接口。这种设计使得系统的各个部分可以独立演进,但也可能导致较多的层间调用和性能开销。

松散分层架构

松散分层架构允许上层直接访问底层的某些服务或资源,从而减少层间调用的开销。这种设计在某些性能敏感的场景中非常有效,但需要小心管理依赖关系,避免系统变得难以维护。

2、DDD分层架构如何推动架构演进

业务和技术不断变化,领域模型也会随之演进,从而影响微服务的功能和边界。通过DDD分层架构,我们可以实现领域模型和微服务的同步演进,推动微服务架构的演进 。

2.1 微服务架构的演进

在微服务架构的演进过程中,DDD分层架构提供了一种清晰的模型,通过明确各层的职责和边界,使得系统的扩展和维护更加便捷。各层之间通过接口进行通信,实现了服务的高内聚、低耦合。

2.2 微服务内服务的演进

在微服务内部,服务的演进可以通过领域模型的重构和优化来实现。通过引入新的领域对象和服务,改进现有的业务逻辑,确保系统能够灵活应对业务需求的变化。

3、三层架构如何演进到DDD分层架构

传统企业应用大多是单体架构,而单体架构多采用三层架构。三层架构可以部分解决程序内代码间调用复杂、代码职责不清的问题,但这种分层是逻辑概念,在物理上它仍然是集中式架构,所以并不适合分布式微服务架构 。

其实,DDD分层架构内的基本要素和三层架构类似,只不过在DDD分层架构中,这些要素被重新归类,划分到了不同的层,确定了层与层之间的交互规则和职责边界。在三层架构向DDD分层架构演进时,主要变化发生在业务逻辑层和数据访问层 。

业务逻辑层的变化

DDD分层架构对三层架构的业务逻辑层进行了更清晰的划分,改善了三层架构核心业务逻辑混乱、代码改动相互影响大的问题。DDD分层架构将三层架构业务逻辑层的业务逻辑拆分到了应用层和领域层,分别以应用服务和领域服务等形式存在。应用服务实现服务的组合和编排,领域服务完成核心领域逻辑,应用服务可以快速响应前端业务和流程的变化,而领域层则更加专注领域模型和实现领域逻辑 。

数据访问层的变化

数据访问层的变化主要发生在数据访问层和基础层之间。三层架构数据访问采用DAO方式,而DDD分层架构对数据库等基础资源访问时采用了仓储设计模式,领域层可以通过仓储接口访问基础资源的实现逻辑。这样,通过依赖倒置实现了各层对基础资源的解耦。原来三层架构的第三方工具包、驱动、Common、Utility、Config等通用的、公共的基础资源统一放到了基础层 。

另外,DDD分层架构在用户接口层引入了DTO和facade接口,可以给前端应用提供更灵活的数据和接口适配能力 。

4、 本章小结

DDD分层架构是微服务设计和开发的核心框架。通过用户接口层、应用层、领域层和基础层这些层次划分,可以明确微服务内各层的职能,划定各领域对象的边界,确定各领域对象的依赖和协作方式 。

传统企业架构向DDD分层架构的转变,可以通过重构业务逻辑层和数据访问层,采用领域驱动设计的原则和方法,逐步实现系统的演进和优化 。

================================

DDD分层架构详解

领域驱动设计(DDD,Domain-Driven Design)是一种设计方法论,旨在通过紧密结合业务领域和软件设计来解决复杂业务问题。DDD提倡从业务需求出发,建立清晰的领域模型,并根据该模型设计系统架构。在DDD的实现中,分层架构是关键的设计模式之一。本文将详细探讨DDD分层架构的各个方面,包括其基本概念、各层职责、实现策略及其在实际项目中的应用。

1. DDD分层架构的历史与演变

DDD分层架构最早的形式是一种各层都依赖于基础层的传统四层架构。在这种架构中,基础层位于核心位置,其他各层依赖于基础层。然而,随着软件架构的不断发展,这种依赖关系逐渐暴露出问题。为了优化架构设计,依赖倒置原则被引入,各层通过接口访问基础层,实现了对基础层的解耦。

1.1 分层架构的演变

分层架构的演变经历了多个阶段,主要包括三层架构、传统四层架构和优化后的四层架构。

  1. 三层架构:传统的三层架构包括表示层、业务逻辑层和数据访问层。这种架构可以部分解决代码职责不清的问题,但在物理上仍然是集中式架构,不适合分布式微服务架构。

  2. 传统四层架构:传统四层架构在三层架构的基础上增加了基础层,各层都依赖于基础层。然而,这种设计并没有充分考虑领域层的重要性,导致依赖关系不合理。

  3. 优化后的四层架构:优化后的四层架构通过引入依赖倒置原则,各层通过仓储接口访问基础层,实现了对基础层的解耦,明确了领域层的核心地位。

2. DDD分层架构的组成

DDD分层架构通常包括四层,从上到下依次是:用户接口层、应用层、领域层和基础层。每一层都有明确的职责和边界,彼此之间通过接口进行通信。

  1. 用户接口层(User Interface Layer):负责接收用户的输入和返回处理结果。

  2. 应用层(Application Layer):负责服务的组合和编排,实现业务逻辑。

  3. 领域层(Domain Layer):包含领域模型和领域逻辑,是系统的核心,负责实现核心业务逻辑。

  4. 基础层(Infrastructure Layer):提供通用的技术和基础服务,包括数据持久化、消息传递等。

2.1 用户接口层

用户接口层是系统与外部交互的部分,负责处理用户的输入并将处理结果返回给用户。用户接口层通过API网关连接前端应用和后端微服务。

2.1.1 用户接口层的职责
  • 接收用户输入:通过API接收前端或其他系统的请求。

  • 展示处理结果:将应用层处理的结果通过API返回给前端或其他系统。

  • 输入验证:对用户输入的数据进行初步验证,确保数据格式和内容的合法性。

2.1.2 用户接口层的实现

用户接口层通常通过RESTful API或GraphQL等技术实现。例如:

@RestController
@RequestMapping("/orders")
public class OrderController {private final OrderApplicationService orderApplicationService;public OrderController(OrderApplicationService orderApplicationService) {this.orderApplicationService = orderApplicationService;}@PostMappingpublic ResponseEntity<Void> placeOrder(@RequestBody OrderDTO orderDTO) {orderApplicationService.placeOrder(orderDTO);return ResponseEntity.status(HttpStatus.CREATED).build();}@GetMapping("/{id}")public ResponseEntity<OrderDTO> getOrder(@PathVariable String id) {OrderDTO orderDTO = orderApplicationService.getOrder(id);return ResponseEntity.ok(orderDTO);}
}
2.2 应用层

应用层负责协调用户接口层和领域层,执行应用逻辑。应用层不包含领域逻辑,只负责调用领域层的功能,处理用户请求并返回结果。

2.2.1 应用层的职责
  • 服务编排:根据业务需求,调用多个领域服务,实现业务功能。

  • 事务管理:管理业务操作的事务,确保数据一致性。

  • 安全控制:处理用户权限和身份验证,确保只有合法用户可以执行操作。

2.2.2 应用层的实现

应用层通常通过应用服务(Application Services)来实现。应用服务是应用层的核心组件,负责处理具体的业务操作。以下是一个典型的应用服务实现示例:

public class OrderApplicationService {private final OrderRepository orderRepository;private final PaymentService paymentService;public OrderApplicationService(OrderRepository orderRepository, PaymentService paymentService) {this.orderRepository = orderRepository;this.paymentService = paymentService;}public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);paymentService.processPayment(order.getPaymentDetails());}public OrderDTO getOrder(String orderId) {Order order = orderRepository.findById(orderId);return new OrderDTO(order);}
}
2.3 领域层

领域层是DDD分层架构的核心,负责处理系统的业务逻辑。领域层包含领域模型和领域服务,通过对领域对象和领域行为的建模,实现业务需求。

2.3.1 领域层的组成

领域层通常包含以下组件:

  • 实体(Entity):具有唯一标识符的对象,表示业务中的关键概念。

  • 值对象(Value Object):无唯一标识符的对象,表示业务中的描述性概念。

  • 聚合(Aggregate):一组相关对象的集合,以聚合根(Aggregate Root)为唯一入口。

  • 领域服务(Domain Service):处理跨实体的业务逻辑。

  • 仓储(Repository):负责实体的持久化和检索。

2.3.2 领域层的职责
  • 建模业务逻辑:通过实体、值对象和聚合等模型来表示业务逻辑。

  • 执行业务操作:通过领域服务执行复杂的业务操作。

  • 维护数据一致性:确保领域模型的状态在业务操作后保持一致。

2.3.3 领域层的实现

领域层的实现需要结合具体的业务需求进行设计。以下是一个简单的领域层实现示例:

public class Order {private OrderId id;private List<OrderItem> items;private OrderStatus status;public Order(OrderId id, List<OrderItem> items) {this.id = id;this.items = items;this.status = OrderStatus.CREATED;}public void addItem(OrderItem item) {items.add(item);}public void removeItem(OrderItem item) {items.remove(item);}public void place() {if (items.isEmpty()) {throw new IllegalStateException("Cannot place an order with no items.");}this.status = OrderStatus.PLACED;}// getters and other methods
}
2.4 基础层

基础层提供系统运行所需的技术支持和基础服务。基础层的设计需要考虑系统的性能、可靠性和可扩展性。

2.4.1 基础层的职责
  • 数据持久化:负责将领域对象持久化到数据库中。

  • 消息传递:处理系统内外部的消息传递,如事件总线、消息队列等。

  • 第三方集成:与外部系统或服务集成,如支付网关、邮件服务等。

2.4.2 基础层的实现

基础层的实现通常涉及数据库访问、消息中间件、外部服务调用等。以下是一个基础设施层的简单实现示例:

public class JpaOrderRepository implements OrderRepository {private final EntityManager entityManager;public JpaOrderRepository(EntityManager entityManager) {this.entityManager = entityManager;}@Overridepublic void save(Order order) {entityManager.persist(order);}@Overridepublic Order findById(OrderId id) {return entityManager.find(Order.class, id);}
}
3. DDD分层架构的重要原则

DDD分层架构有一个重要的依赖原则:“每层只能与位于其下方的层发生耦合”。根据耦合的紧密程度,可以分为两种架构模式:严格分层架构和松散分层架构。

3.1 严格分层架构

严格分层架构要求每一层只能依赖于其下层的接口。这种设计使得系统的各个部分可以独

立演进,但也可能导致较多的层间调用和性能开销。

3.2 松散分层架构

松散分层架构允许上层直接访问底层的某些服务或资源,从而减少层间调用的开销。这种设计在某些性能敏感的场景中非常有效,但需要小心管理依赖关系,避免系统变得难以维护。

4. DDD分层架构的优势

DDD分层架构通过明确各层的职责和边界,实现了系统的高内聚、低耦合,具有以下优势:

  • 提高系统可维护性:每一层都有明确的职责和边界,代码更加清晰,便于维护和扩展。

  • 增强系统灵活性:通过分层设计,可以在不影响其他层的情况下,对某一层进行修改和优化。

  • 促进团队协作:不同层次的职责划分明确,团队成员可以专注于各自负责的层次,提高开发效率。

5. DDD分层架构的实践

在实际项目中,DDD分层架构的应用需要结合具体的业务需求和技术环境进行调整。以下是一些实践建议:

5.1 选择合适的分层策略

根据系统的复杂度和业务需求,选择合适的分层策略。对于小型项目,可以采用简化的三层架构;对于大型项目,则可以采用完整的四层架构。

5.2 遵循依赖倒置原则

在DDD分层架构中,低层不应该依赖于高层,高层应该通过接口依赖于低层。这一原则通过依赖倒置(Dependency Inversion Principle, DIP)来实现,有助于降低层之间的耦合。

5.3 结合CQRS模式

命令查询责任分离(Command Query Responsibility Segregation, CQRS)是一种常见的设计模式,将写操作和读操作分离,以提高系统的性能和扩展性。在DDD分层架构中,可以结合CQRS模式,实现更加灵活的架构设计。

5.4 应用事件驱动架构

事件驱动架构(Event-Driven Architecture, EDA)是一种基于事件的系统设计模式,适用于处理复杂业务逻辑和高并发场景。在DDD分层架构中,可以通过领域事件和事件总线,实现各层之间的解耦和异步处理。

5.5 实现自动化测试

自动化测试是确保系统质量的重要手段。在DDD分层架构中,可以通过单元测试、集成测试和端到端测试等多种方式,对各层进行全面测试,确保系统的稳定性和可靠性。

6. 案例分析:电商系统的DDD分层架构

为了更好地理解DDD分层架构的应用,以下以一个电商系统为例,进行详细的案例分析。

6.1 需求分析

一个典型的电商系统需要处理以下业务需求:

  • 用户管理:注册、登录、用户信息管理等。

  • 商品管理:商品的增删改查、分类管理、库存管理等。

  • 订单管理:订单创建、支付、配送、订单状态管理等。

  • 促销管理:优惠券、折扣活动等。

6.2 系统架构设计

根据以上需求,可以设计一个基于DDD分层架构的电商系统。系统架构图如下:

+--------------------+
|  用户接口层        |
+--------------------+
|  应用层            |
+--------------------+
|  领域层            |
+--------------------+
|  基础设施层        |
+--------------------+
6.3 各层职责与实现

用户接口层:负责处理用户的注册、登录、浏览商品、下单等操作。可以使用前端框架(如React、Vue)实现。

应用层:负责协调用户接口层和领域层,处理用户请求并返回结果。包括用户服务、商品服务、订单服务等。

public class OrderApplicationService {private final OrderRepository orderRepository;private final PaymentService paymentService;public OrderApplicationService(OrderRepository orderRepository, PaymentService paymentService) {this.orderRepository = orderRepository;this.paymentService = paymentService;}public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);paymentService.processPayment(order.getPaymentDetails());}public OrderDTO getOrder(String orderId) {Order order = orderRepository.findById(orderId);return new OrderDTO(order);}
}

领域层:包含用户、商品、订单等领域模型及其业务逻辑。通过实体、值对象、聚合等模型表示业务逻辑。

public class Order {private OrderId id;private List<OrderItem> items;private OrderStatus status;public Order(OrderId id, List<OrderItem> items) {this.id = id;this.items = items;this.status = OrderStatus.CREATED;}public void addItem(OrderItem item) {items.add(item);}public void removeItem(OrderItem item) {items.remove(item);}public void place() {if (items.isEmpty()) {throw new IllegalStateException("Cannot place an order with no items.");}this.status = OrderStatus.PLACED;}// getters and other methods
}

基础设施层:提供数据持久化、消息传递等服务。包括数据库访问层、消息队列等。

public class JpaOrderRepository implements OrderRepository {private final EntityManager entityManager;public JpaOrderRepository(EntityManager entityManager) {this.entityManager = entityManager;}@Overridepublic void save(Order order) {entityManager.persist(order);}@Overridepublic Order findById(OrderId id) {return entityManager.find(Order.class, id);}
}
6.4 应用CQRS和事件驱动架构

在电商系统中,可以结合CQRS和事件驱动架构,实现读写操作的分离和事件处理的解耦。

CQRS:将订单的写操作和读操作分离,通过命令总线处理写操作,通过查询总线处理读操作。

事件驱动架构:在订单创建、支付完成、订单状态变更等关键操作时,发布领域事件,通过事件总线传递给订阅者,实现各服务之间的异步解耦。

// 订单创建事件
public class OrderCreatedEvent {private String orderId;private String userId;private LocalDateTime createTime;// 构造函数、getter和setter方法
}// 发布订单创建事件
public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);OrderCreatedEvent event = new OrderCreatedEvent(order.getId(), order.getUserId(), LocalDateTime.now());eventBus.publish(event);
}// 处理订单创建事件
public class OrderCreatedEventHandler {@Subscribepublic void handle(OrderCreatedEvent event) {// 处理订单创建后的业务逻辑}
}
7. 总结

DDD分层架构通过明确各层的职责和边界,实现了系统的高内聚、低耦合,提高了系统的可维护性和扩展性。在实际项目中,应用DDD分层架构需要结合具体的业务需求和技术环境,选择合适的分层策略,并结合CQRS和事件驱动架构等设计模式,实现灵活高效的系统设计。

通过对DDD分层架构的深入理解和实践应用,我们可以构建出更加健壮和灵活的系统,更好地应对复杂业务需求和快速变化的技术环境。

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

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

相关文章

【uniapp-ios】App端与webview端相互通信的方法以及注意事项

前言 在开发中&#xff0c;使用uniapp开发的项目开发效率是极高的&#xff0c;使用一套代码就能够同时在多端上线&#xff0c;像笔者之前写过的使用Flutter端和webview端之间的相互通信方法和问题&#xff0c;这种方式本质上实际上是h5和h5之间的通信&#xff0c;网上有非常多…

物联网实训室建设可行性报告

一、建设物联网实训室的目的和意义 随着信息技术的快速发展&#xff0c;物联网&#xff08;IoT&#xff09;已成为推动社会进步和经济发展的关键技术之一。物联网技术的集成应用&#xff0c;不仅能够提高生产效率&#xff0c;还能促进智慧城市、智能家居、智能农业等多个领域的…

python04——类(基础new)

类其实也是一种封装的思想&#xff0c;类就是把变量、方法等封装在一起&#xff0c;然后可以通过不同的实例化对其进行调用操作。 1.类的定义 class 类名&#xff1a; 变量a def __init__ (self,参数2&#xff0c;参数2...)&#xff1a;初始化函数&#xff01;&#xff01;&…

简单实现联系表单Contact Form自动发送邮件

如何实现简单Contact Form自动邮件功能&#xff1f;怎样简单设置&#xff1f; 联系表单不仅是访客与网站所有者沟通的桥梁&#xff0c;还可以收集潜在客户的信息&#xff0c;从而推动业务的发展。AokSend将介绍如何简单实现一个联系表单&#xff0c;自动发送邮件的过程&#x…

【游戏客户端】大话slg玩法架构(一)滚动基类

【游戏客户端】大话slg玩法架构&#xff08;一&#xff09;滚动基类 大家好&#xff0c;我是Lampard家杰~~ 今天我们兑现诺言&#xff0c;给大家分享SLG玩法的实现j架构&#xff0c;关于SLG玩法的介绍可以参考这篇上一篇文章&#xff1a;【游戏客户端】制作率土之滨Like玩法 PS…

机器学习统计学基础 - 最大似然估计

最大似然估计&#xff08;Maximum Likelihood Estimation, MLE&#xff09;是一种常用的参数估计方法&#xff0c;其基本原理是通过最大化观测数据出现的概率来寻找最优的参数估计值。具体来说&#xff0c;最大似然估计的核心思想是利用已知的样本结果&#xff0c;反推最有可能…

binutils ifunc 流程图

上图是x86 binutils 的流程图。 函数说明_bfd_x86_elf_link_hash_table_createInit local STT_GNU_IFUNC symbol hash.elf_x86_64_check_relocsAdd support for handling STT_GNU_IFUNC symbols_bfd_elf_x86_get_local_sym_hashFind and/or create a hash entry for local sym…

Leetcode—97. 交错字符串【中等】

2024每日刷题&#xff08;140&#xff09; Leetcode—97. 交错字符串 2d动规实现代码 class Solution { public:bool isInterleave(string s1, string s2, string s3) {int m s1.length();int n s2.length();int len s3.length();if(m n ! len) {return false;}vector<…

SpringBoot日常:封装rabbitmq starter组件

文章目录 逻辑实现RabbitExchangeEnumRabbitConfigRabbitModuleInfoRabbitModuleInitializerRabbitPropertiesRabbitProducerManagerPOM.xmlspring.factories 功能测试application.yml配置生产者&#xff1a;消费者&#xff1a;测试结果&#xff1a;总结 本章内容主要介绍编写一…

stm32 USB CDC类虚拟串口初体验

1. 目标 本文介绍CubeMX生成 USB CDC类虚拟串口工程的操作步骤。 2. 配置流程 时钟配置 usb外设需要48M时钟输入 stm32405使用外部时钟源HSE,否则配不出来48M时钟stm32h750内部有一个48M时钟 stm32f405时钟配置 stm32h750时钟配置 Connectivity ->USB_OTG_FS 和 Connect…

C++初阶:从C过渡到C++的入门基础

✨✨所属专栏&#xff1a;C✨✨ ✨✨作者主页&#xff1a;嶔某✨✨ C发展历史 C的起源可以追溯到1979年&#xff0c;当时BjarneStroustrup(本贾尼斯特劳斯特卢普&#xff0c;这个翻译的名字不同的地⽅可能有差异)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复…

JavaDS —— 顺序表ArrayList

顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存储。在数组上完成数据的增删查改。在物理和逻辑上都是连续的。 模拟实现 下面是我们要自己模拟实现的方法&#xff1a; 首先我们要创建一个顺序表&#xff0c;顺序表…

关于Mars3d的入门

关于Mars3d的入门 一. 创建地球&#xff0c;加载瓦片图层二 矢量图层2.1 常用矢量图层2.1.1 GraphicLayer2.1.2 GeoJsonLayer 2.2 矢量图层的点击事件 三 矢量数据四 事件机制 一. 创建地球&#xff0c;加载瓦片图层 // 1. 创建地球let map new mars3d.Map("mars3dContai…

从零开始做题:My_lllp

题目 给出一张png图片 解题 ┌──(holyeyes㉿kali2023)-[~/Misc/题目/zulu/My_lllp] └─$ python2 lsb.py extract my_lllp.png out.txt my_lllp [] Image size: 1080x1079 pixels. [] Written extracted data to out.txt. ┌──(holyeyes㉿kali2023)-[~/Misc/题目/zul…

简易Qt串口助手

界面显示如下 关于串口类 初始化 设置串口号 设置波特率 打开串口 发送按钮功能实现 接收数据显示在控件中 关闭串口

使用 MFA 保护对企业应用程序的访问

多因素身份验证&#xff08;MFA&#xff09;是在授予用户访问特定资源的权限之前&#xff0c;使用多重身份验证来验证用户身份的过程&#xff0c;仅使用单一因素&#xff08;传统上是用户名和密码&#xff09;来保护资源&#xff0c;使它们容易受到破坏&#xff0c;添加其他身份…

springboot非物质文化遗产管理系统-计算机毕业设计源码16087

目录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 2.2.5 修改信息流程 2.2.6 删除信息流程 2.3 系统功能…

前端开发过程中经常遇到的问题以及对应解决方法 (持续更新)

我的朋友已经工作了 3 年&#xff0c;他过去一直担任前端工程师。 不幸的是&#xff0c;他被老板批评了&#xff0c;因为他在工作中犯了一个错误&#xff0c;这是一个非常简单但容易忽视的问题&#xff0c;我想也是很多朋友容易忽视的一个问题。 今天我把它分享出来&#xff…

Linux三剑客(grep、awk和sed)操作及与管道结合使用

1. 总览 grep、sed和awk被称为Linux三剑客&#xff0c;是因为它们在文本处理和数据操作方面极其强大且常用。 Linux三剑客在文件处理中的作用&#xff1a; grep&#xff08;数据查找定位&#xff09;&#xff1a;文本搜索工具&#xff0c;在文件中搜索符合正则表达式的文本内容…

Redis原理-数据结构

Redis原理篇 1、原理篇-Redis数据结构 1.1 Redis数据结构-动态字符串 我们都知道Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串&#xff0c;因为C语言字符串存…