DDD - 概念复习

news/2025/9/21 11:46:48/文章来源:https://www.cnblogs.com/tangge/p/19103351

领域

在 DDD 中,“领域(Domain)” 指的是软件要解决的 “业务范围” 及其包含的所有业务概念、规则和逻辑

简单来说:

  • 如果你开发的是 “电商系统”,那么 “电商” 就是核心领域,包含 “商品、订单、支付、物流” 等子业务范围;
  • 如果你开发的是 “医院挂号系统”,那么 “医疗挂号” 就是核心领域,包含 “患者、医生、排班、挂号单” 等子业务范围。

领域的本质是 “业务的边界和内容”,DDD 的所有设计都围绕 “如何精准映射领域” 展开。

领域的层级划分:从宏观到微观

层级 定义 示例(电商领域)
核心领域 业务的核心价值所在,是企业竞争力的关键,需要投入最多资源设计。 订单履约(下单、库存扣减、支付联动)
支撑领域 为核心领域提供支持,但不直接产生核心价值,可复用或简化设计。 商品管理(商品上架、分类、定价)
通用领域 跨领域复用的基础能力,与具体业务关联弱,可通过开源组件或通用服务实现。 用户认证、日志记录、短信通知

领域模型(对领域的抽象)

1、对于领域内的对象进行建模,从而抽象出来模型。以银行为例。
2、我们的项目应该开始于创建领域模型,而不是考虑如何设计数据库和编写代码。使用领域模型,我们可以一直用业务语言去描述和构建系统,而不是使用技术人员的语言。

通用语言和界限上下文

通用语言

1、“我想要商品可以被删除”→“我想要把删除的还原回来”→"Windows回收站都能
2、此"用户"非彼"用户
3、通用语言:一个拥有确切含义的、没有二义性的语言。

界限上下文

通用语言离不开特定的语义环境,只有确定了通用语言所在的边界,才能没有歧义的描述一个业务对象。

总结

  • 通用语言是 “内容”,解决 “说什么” 的问题,确保团队对业务的理解一致;
  • 限界上下文是 “容器”,解决 “在哪里说” 的问题,确保语言在合适的范围内有效;
  • 二者结合,既保证了每个子领域的内聚性(语言统一),又控制了整体系统的复杂度(边界清晰),是 DDD 解决复杂业务问题的核心方法论。

实体和值对象

实体(Entity)

核心特征

  • 有唯一标识符(ID),通过 ID 区分不同实例(即使属性完全相同,ID 不同就是不同实体);
  • 状态可随业务流程变化(具有生命周期);
  • 封装自身的业务行为和状态变更规则。

适用场景

代表业务中 “有身份、可变化” 的事物,如订单、用户、商品等。

// 订单ID(使用值对象封装ID,更具业务含义)
public record OrderId(Guid Value);// 订单状态(枚举表示状态变更)
public enum OrderStatus { Pending, Paid, Shipped, Completed, Cancelled }// 订单项(实体,属于订单聚合)
public class OrderItem
{public Guid ProductId { get; }public string ProductName { get; }public decimal UnitPrice { get; }public int Quantity { get; }public decimal TotalPrice => UnitPrice * Quantity;public OrderItem(Guid productId, string productName, decimal unitPrice, int quantity){if (quantity <= 0) throw new ArgumentException("数量必须大于0");if (unitPrice < 0) throw new ArgumentException("单价不能为负数");ProductId = productId;ProductName = productName;UnitPrice = unitPrice;Quantity = quantity;}
}// 订单实体(核心实体)
public class Order
{// 唯一标识(实体的核心特征)public OrderId Id { get; }// 状态(可变化的属性)public OrderStatus Status { get; private set; }// 订单项集合public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();private readonly List<OrderItem> _items = new();// 下单时间(创建后不变)public DateTime CreatedTime { get; }// 支付时间(状态变更时赋值)public DateTime? PaidTime { get; private set; }// 构造函数(初始化实体,设置初始状态)public Order(OrderId id){Id = id;Status = OrderStatus.Pending;CreatedTime = DateTime.UtcNow;}// 业务行为:添加订单项(封装规则)public void AddItem(OrderItem item){if (Status != OrderStatus.Pending)throw new InvalidOperationException("只有待支付订单可以添加商品");_items.Add(item);}// 业务行为:支付订单(状态变更规则)public void Pay(){if (Status != OrderStatus.Pending)throw new InvalidOperationException("只有待支付订单可以支付");if (!Items.Any())throw new InvalidOperationException("订单没有商品,无法支付");Status = OrderStatus.Paid;PaidTime = DateTime.UtcNow;}// 业务行为:取消订单(状态变更规则)public void Cancel(){if (Status is OrderStatus.Shipped or OrderStatus.Completed)throw new InvalidOperationException("已发货或已完成的订单不能取消");Status = OrderStatus.Cancelled;}
}

实体设计要点

  1. ID 不可变:通常在构造函数中初始化,不提供修改 ID 的方法;
  2. 行为优先:将状态变更逻辑封装为方法(如 Pay()Cancel()),而非直接暴露 setter
  3. 相等性判断:重写 Equals 时以 ID 为依据(示例中 OrderIdrecord 类型自动实现值相等)。

值对象(Value Object)

核心特征

  • 无唯一标识符,通过属性值判断相等性;
  • 不可变(创建后属性不能修改);
  • 描述事物的 “属性或特征”,而非事物本身。

适用场景

代表 “属性组合” 或 “无身份的概念”,如地址、金额、颜色等。

C# 示例:地址和金额值对象

// 地址值对象(描述位置属性)
public class Address : IEquatable<Address>
{// 不可变属性(无setter)public string Province { get; }public string City { get; }public string Street { get; }public string ZipCode { get; }// 构造函数初始化所有属性,并验证有效性public Address(string province, string city, string street, string zipCode){Province = string.IsNullOrWhiteSpace(province) ? throw new ArgumentException("省份不能为空") : province;City = string.IsNullOrWhiteSpace(city) ? throw new ArgumentException("城市不能为空") : city;Street = string.IsNullOrWhiteSpace(street) ? throw new ArgumentException("街道不能为空") : street;ZipCode = string.IsNullOrWhiteSpace(zipCode) ? throw new ArgumentException("邮编不能为空") : zipCode;}// 重写相等性判断(基于所有属性值)public bool Equals(Address? other){if (other is null) return false;return Province == other.Province && City == other.City && Street == other.Street && ZipCode == other.ZipCode;}public override bool Equals(object? obj) => Equals(obj as Address);public override int GetHashCode() => HashCode.Combine(Province, City, Street, ZipCode);// 提供便捷的解构方法public void Deconstruct(out string province, out string city, out string street, out string zipCode){province = Province;city = City;street = Street;zipCode = ZipCode;}
}// 金额值对象(描述数值+币种)
public record Money(decimal Amount, string Currency)
{// 静态验证逻辑(确保创建的值对象有效)public static Money Create(decimal amount, string currency){if (amount < 0) throw new ArgumentException("金额不能为负数");if (string.IsNullOrWhiteSpace(currency)) throw new ArgumentException("币种不能为空");return new Money(amount, currency);}// 提供领域行为(如金额相加,需确保币种一致)public Money Add(Money other){if (Currency != other.Currency)throw new InvalidOperationException("不同币种不能相加");return new Money(Amount + other.Amount, Currency);}
}

值对象设计要点

  1. 不可变性:所有属性设为 get-only,通过构造函数一次性初始化;
  2. 值相等性:重写 EqualsGetHashCode,基于所有属性值判断相等;
  3. 自我验证:在构造函数中验证属性有效性(如金额不能为负);
  4. 行为封装:包含与自身属性相关的逻辑(如 Money.Add() 确保币种一致)。

实体与值对象的核心区别

维度 实体(Entity) 值对象(Value Object)
标识 有唯一 ID(身份标识) 无 ID(通过属性值标识)
可变性 状态可随业务变化 不可变(创建后无法修改)
相等性 基于 ID 判断相等 基于属性值判断相等
生命周期 有明确的创建、修改、删除过程 通常随所属实体创建 / 销毁
示例 订单、用户、商品 地址、金额、坐标

实践建议

  • 优先设计值对象:将 “属性组合” 封装为值对象(如 Address),可减少实体复杂度;
  • 实体依赖值对象:实体通常包含多个值对象(如订单包含收货地址 Address);
  • record 简化值对象:C# 9+ 的 record 类型自动实现值相等性,适合快速定义简单值对象(如 Money)。

通过合理区分实体和值对象,能让领域模型更贴合业务本质,同时提升代码的可读性和可维护性。

聚合和聚合根

聚合 (Aggregate) 是一组相关联的领域对象的集合,它们被视为一个整体来处理。聚合根 (Aggregate Root) 是聚合中作为访问入口点的对象,它负责维护聚合的完整性和一致性。

1、目的:高内聚,低耦合。有关系的实体紧密协作,而关系很弱的实体被隔离
2、把关系紧密的实体放到一个聚合中,每个聚合中有实体作为 聚合根(Aggregate Root),所有对于聚合内对象的访问都通过聚合根来进行,外部对象只能持有对聚合根的引用
3、聚合根不仅仅是实体,还是所在聚合的管理者。

购物车例子:

using System;
using System.Collections.Generic;
using System.Linq;// 聚合根:购物车(实体)
public class Cart
{private readonly List<CartItem> _items = new List<CartItem>();public Guid Id { get; }public string UserId { get; }public IReadOnlyCollection<CartItem> Items => _items.AsReadOnly();// 其他属性和方法与之前相同...private Cart(Guid id, string userId){Id = id;UserId = userId ?? throw new ArgumentNullException(nameof(userId));}public static Cart Create(string userId){return new Cart(Guid.NewGuid(), userId);}// 添加带产品信息值对象的方法public void AddItem(ProductInfo product, int quantity){if (quantity <= 0)throw new ArgumentException("数量必须大于0", nameof(quantity));var existingItem = _items.FirstOrDefault(i => i.Product.ProductId == product.ProductId);if (existingItem != null){existingItem.UpdateQuantity(existingItem.Quantity + quantity);}else{_items.Add(new CartItem(product, quantity));}}
}// 购物项(实体)
public class CartItem
{// 产品信息(值对象)public ProductInfo Product { get; }public int Quantity { get; private set; }public decimal TotalPrice => Product.UnitPrice * Quantity;public CartItem(ProductInfo product, int quantity){Product = product ?? throw new ArgumentNullException(nameof(product));Quantity = quantity > 0 ? quantity : throw new ArgumentException("数量必须大于0", nameof(quantity));}internal void UpdateQuantity(int newQuantity){if (newQuantity <= 0)throw new ArgumentException("数量必须大于0", nameof(newQuantity));Quantity = newQuantity;}
}// 产品信息(值对象)
public class ProductInfo
{public string ProductId { get; }public string Name { get; }public decimal UnitPrice { get; }public string Description { get; }// 值对象通常是不可变的(构造后不能修改)public ProductInfo(string productId, string name, decimal unitPrice, string description){ProductId = productId ?? throw new ArgumentNullException(nameof(productId));Name = name ?? throw new ArgumentNullException(nameof(name));UnitPrice = unitPrice >= 0 ? unitPrice : throw new ArgumentException("单价不能为负数", nameof(unitPrice));Description = description ?? string.Empty;}// 值对象需要重写相等性检查public override bool Equals(object obj){return obj is ProductInfo info &&ProductId == info.ProductId &&Name == info.Name &&UnitPrice == info.UnitPrice &&Description == info.Description;}public override int GetHashCode(){return HashCode.Combine(ProductId, Name, UnitPrice, Description);}
}
  1. 聚合根 (Cart) 是整个聚合的入口点,外部只能通过它来操作购物车中的商品
  2. 聚合规则
    • 购物项 (CartItem) 不能独立存在,必须属于某个购物车
    • 所有对购物项的操作(添加、修改、删除)都必须通过购物车进行
    • 购物车确保了业务规则(如数量不能为负)
  3. 仓储设计:只存在 ICartRepository,没有 ICartItemRepository,因为购物项不能独立持久化

这种设计保证了购物车数据的一致性,例如不会出现数量为负的购物项,也不会出现不属于任何购物车的孤立购物项。

在上面的购物车 (Cart) 聚合中,我们也可以清晰地区分实体 (Entity) 和值对象 (Value Object):

  1. 实体 (Entity):具有唯一标识,其身份不依赖于属性,即使属性变化,实体身份依然保持不变

    • Cart(购物车):是实体,也是聚合根
      • 有唯一标识Id
      • 即使购物车中的商品(属性)发生变化,购物车本身的身份依然不变
      • 生命周期独立,有自己的创建、修改、删除等状态变化
    • CartItem(购物项):是实体
      • 虽然没有显式定义Id,但通过ProductId在购物车范围内具有唯一标识
      • 它的身份由 "属于哪个购物车" 和 "哪个商品" 共同确定
      • 可以独立修改(如更新数量)而保持身份不变
  2. 值对象 (Value Object):没有唯一标识,其身份由属性值共同决定,属性相同则视为相同对象

    在我们的示例中没有显式定义值对象,但可以扩展一个来更好地理解:

聚合,聚合根,实体,值对象的关系,

聚合(Aggregate)
├─ 聚合根(Aggregate Root) → 实体(Entity)
│  ├─ 其他实体(Entity)
│  └─ 值对象(Value Object)
└─ 其他实体(Entity)└─ 值对象(Value Object)
  1. 实体 (Entity) 与值对象 (Value Object):领域模型的基础元素
    • 两者都是领域中的具体概念,是构成聚合的基本单元
    • 实体:有唯一标识,身份优先于属性(例如:用户、订单)
    • 值对象:无唯一标识,属性组合决定其身份,且不可变(例如:地址、金额、颜色)
    • 关系:值对象可以作为实体的属性存在;实体可以包含多个值对象
  2. 聚合 (Aggregate):实体和值对象的有机组合
    • 聚合是一组紧密相关的实体和值对象的集合,被视为一个不可分割的整体
    • 目的:保证领域模型的一致性,避免因分散修改导致的数据不一致
    • 规则:聚合内部的对象可以相互引用,但外部对象只能通过聚合根访问聚合内部成员
  3. 聚合根 (Aggregate Root):聚合的 "大门"
    • 聚合根是聚合中唯一对外暴露的实体,是外部访问聚合的唯一入口
    • 职责:
      • 维护聚合内部的业务规则和数据一致性
      • 负责聚合内部对象的创建和管理
      • 作为与外部对象交互的 "代理人"
    • 特征:
      • 必须是实体(有唯一标识)
      • 聚合中只能有一个聚合根
      • 仓储 (Repository) 只针对聚合根设计

购物车领域模型关系图

购物车聚合(CartAggregate)
├─ 聚合根:购物车(Cart) → 实体
│  ├─ 购物项(CartItem) → 实体
│  │  ├─ 产品信息(ProductInfo) → 值对象
│  │  └─ 数量(Quantity) → 实体属性
│  └─ 用户ID(UserId) → 实体属性
└─ 优惠信息(Discount) → 值对象

各概念在购物车场景中的具体体现

  1. 值对象 (Value Object):关注 "是什么",无唯一标识,不可变
    • ProductInfo(产品信息)
      • 包含属性:产品 ID、名称、单价、描述、图片 URL
      • 特点:属性完全相同则视为同一个对象(比如 "iPhone 15 128G 黑色")
      • 不可变:创建后不能修改(商品信息变更应创建新的 ProductInfo)
    • Discount(优惠信息)
      • 包含属性:优惠码、折扣率、有效期
      • 特点:通过属性组合确定其身份(相同优惠码和折扣率视为同一优惠)
  2. 实体 (Entity):关注 "是谁",有唯一标识,可修改
    • CartItem(购物项)
      • 标识:通过 "所属购物车 + 关联产品 ID" 确定唯一身份
      • 可修改属性:数量(用户可以增减购买数量)
      • 依赖关系:必须属于某个购物车,不能独立存在
    • Cart(购物车)
      • 标识:有全局唯一 ID(CartId)
      • 可修改属性:包含的购物项集合(添加 / 删除 / 修改购物项)
      • 生命周期:有明确的创建(用户打开购物车)、修改(添加商品)、删除(清空或过期)过程
  3. 聚合根 (Aggregate Root):购物车 (Cart)
    • 是购物车聚合的 "入口" 和 "管理者",外部只能通过它访问聚合内的对象
    • 负责维护聚合的一致性:
      • 确保购物项数量不能为负(通过AddItem()方法校验)
      • 防止添加不存在的商品(通过 ProductInfo 验证)
      • 计算购物车总金额(汇总所有购物项的价格)
    • 对外暴露操作接口:AddItem()RemoveItem()UpdateQuantity()
  4. 聚合 (Aggregate):购物车聚合
    • 包含:购物车 (Cart)、购物项 (CartItem)、ProductInfo、Discount
    • 边界规则:
      • 外部不能直接修改 CartItem,必须通过 Cart 的方法
      • 保存购物车时,整个聚合作为一个整体持久化
      • 删除购物车时,所有包含的购物项也会被一同删除
    • 一致性保证:添加商品时自动计算总金额,应用优惠时重新计算价格

总结购物车场景中的关系

  • 值对象是 "静态属性":如商品信息、优惠规则,它们描述事物的特征
  • 实体是 "动态对象":如购物车和购物项,它们有身份和生命周期
  • 聚合根是 "管理者":购物车控制所有内部操作,确保数据一致
  • 聚合是 "完整单元":将相关对象打包,作为一个整体处理(如保存、删除)

这种设计确保了购物车数据的完整性(比如不会出现数量为负的商品),同时符合用户操作购物车的实际业务场景。

领域服务和应用服务

1、聚合中的实体中没有业务逻辑代码,只有对象的创建、对象的初始化、状态管理等个体相关的代码
2、对于聚合内的业务逻辑,我们编写领域服务(DomainService),而对于跨聚协作以及聚合与外部系统协作的逻辑,我们编写应用服务(ApplicationService)
3、应用服务协调多个领域服务、外部系统来完成一个用例。

在购物车场景中,领域服务 (Domain Service) 和应用服务 (Application Service) 承担不同职责,共同完成业务流程。我们通过具体例子来理解它们的区别和协作方式:

核心概念区分

  • 领域服务:封装领域内复杂的业务规则或跨实体 / 聚合的操作,确保领域逻辑的纯粹性
  • 应用服务:协调领域对象完成用户用例,处理事务、权限等技术细节,不包含核心业务规则

关键区别与职责划分

  1. 领域服务 (CartDomainService)
    • 包含核心业务规则:如库存检查、数量限制、折扣计算等聚合中的实体中没有业务逻辑代码,只有对象的创 建、对象的初始化、状态管理等个体相关的代码 2、对于聚合内的业务逻辑,我们编写领域服务 (DomainService),而对于跨聚合协作以及聚合与外 部系统协作的逻辑,我们编写应用服务(Application Service) 3、应用服务协调多个领域服务、外部系统来完成一个 用例。
    • 直接操作领域对象(Cart、CartItem 等)
    • 不依赖基础设施(仓储、日志等),不涉及数据库操作
    • 方法参数通常是领域对象,而非原始类型
    • 示例:AddProductToCart 封装了添加商品的所有业务约束
  2. 应用服务 (CartApplicationService)
    • 负责协调用户用例:如 "添加商品到购物车" 这个完整流程
    • 处理跨领域的技术细节:依赖注入、事务管理、数据持久化
    • 作为用户与领域模型之间的桥梁:接收 DTO / 原始类型参数,返回处理结果
    • 不包含业务规则,而是调用领域服务完成核心逻辑
    • 示例:AddProductToCartAsync 协调了获取数据、调用领域服务、保存结果的完整流程

协作流程说明

当用户执行 "添加商品到购物车" 操作时:

  1. 应用服务接收用户输入(用户 ID、商品 ID、数量)
  2. 应用服务从仓储获取所需的领域对象(购物车、商品信息)
  3. 应用服务调用领域服务处理核心业务逻辑(检查库存、添加商品)
  4. 应用服务将修改后的领域对象保存到仓储
  5. 应用服务返回结果给用户

这种设计确保了业务规则集中在领域服务中,应用服务专注于流程协调,使系统更易于维护和扩展。

仓储(Repository)和工作单元(Unit of Work)

  • 仓储(Repository):封装对数据的访问,为领域模型提供类似集合的接口,隔离领域层与数据访问层
  • 工作单元(Unit of Work):跟踪领域对象的变更,协调多个仓储的操作,确保数据一致性(通常与事务相关),这些工作单元要么全部成功,要么全部失败。

领域事件(Domain Event)集成事件(Integration Event)

  • 领域事件:发生在限界上下文内部的、对领域有意义的事件(如 “订单状态变更”“商品添加到购物车”),用于捕获领域行为的结果,实现领域内的解耦和业务响应。
  • 集成事件:发生在限界上下文之间的事件(如 “订单已创建” 需要通知库存系统、支付系统),用于跨服务 / 上下文的通信,实现分布式系统的协同。
维度 领域事件(Domain Event) 集成事件(Integration Event)
作用范围 限界上下文内部 跨限界上下文 / 服务
通信方式 进程内同步 / 异步(如内存事件总线) 跨进程异步(如消息队列:RabbitMQ、Kafka)
数据粒度 包含领域内详细信息(供内部处理) 仅包含跨服务所需的最小信息(避免耦合)
序列化需求 无需序列化(进程内传递对象) 必须可序列化(跨服务传输)
处理目的 实现领域内业务响应(如状态联动、日志) 实现跨系统协同(如库存扣减、通知)
示例 订单状态变更、购物车商品数量更新 订单创建、支付完成、库存不足

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

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

相关文章

进一步理解自适应卡尔曼滤波(AKF) - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

CSP-J1S1_2025

考点小记与错题整理。考点小记等比数列求和公式 已知等比数列 \(\{a_n\}\) ,公比为 \(q\),前 \(n\) 项和为 \(S_n\) 。 则有 \(S_n = \begin{cases} na_1, &q = 1 \\ \large \frac{a_1(1 - q ^ n)}{1 - q}, &…

完整教程:基于Spring Boot植物销售管理系统的设计与实现

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

​​Final Cut Pro 11.0 for Mac 剪视频安装教程|DMG文件安装步骤详解​(附安装包)

​​Final Cut Pro 11.0 for Mac 剪视频安装教程|DMG文件安装步骤详解​(附安装包)​一、下载文件 首先,你得先把这个 ​​Final Cut Pro 11.0 for Mac.dmg​​ 文件下载到你的 Mac 上。 安装包下载:https://pan.…

Vdd Vcc

Vdd Vcc二、在STM32中的具体含义和关系 对于STM32这类现代MCU,VCC和VDD的用法非常明确: 1. VDD / VDDA含义:I/O端口和外部外设的模拟电源。功能:这是给芯片的GPIO引脚驱动电路、部分外部外设以及模拟-to-数字转换器…

实用指南:物联网赋能24H共享书屋:智能化借阅管理的完整解决方案!

实用指南:物联网赋能24H共享书屋:智能化借阅管理的完整解决方案!2025-09-21 11:30 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !…

基于ThinkPHP实现动态ZIP压缩包的生成

在ThinkPHP框架中生成动态ZIP压缩包涉及到文件处理和压缩包管理,可以通过PHP的ZipArchive类来实现。下面逐步介绍如何在ThinkPHP框架中实现动态ZIP压缩包的生成首先,确保你的PHP环境支持zip扩展。 在你的控制器中添加…

使用Java实现用户的注册和登录流程

第一步:构建用户模型 首先,我们需要一个用户模型,以 Java 类的形式表现: public class User {private String username;private String password; // 注意:实际生产中密码应加密存储// 构造函数、getter 和 sette…

Windows安装Kafka(kafka_2.12-3.9.1),配置Kafka,以及遇到的困难解决方案

Windows安装Kafka(kafka_2.12-3.9.1),配置Kafka,以及遇到的困难解决方案pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family…

准备工作之动态内存分配[基于郝斌课程]

定义一块内存可以用数组定义,也可以动态分配: 使用数组定义一块内存,则该块内存是静态的,也就是一旦定义之后,这块内存的大小就固定了,例如,数组元素个数是5,则定义后,这=这块内存大小就是5,不能再改变 但是…

2025.6第一套六级听力生词

"Escalate" 是一个英语动词,在不同语境下有不同的含义,常见用法包括: 升级/加剧‌ 指问题、冲突或局势的严重性增加。例句:The dispute escalated into a full-scale war.(争端升级为全面战争。) (正…

CSP-S 2025游记

初赛 day -1 赛前最后一次去机房 , 尽管前三年都随便考过了 , 但今年不知道为什么特别紧张 , 害怕考以前没出过的类型 (伏笔) day 0 足球赛 被虐了 , 给腿跑软了 , 顶级后卫这一块 中午一点压力都没有了 , 睡觉是…

Chapter 5 Wrap Perspective

# width, height = 458, 371 width, height = 250, 350pts1 = np.float32([[109, 220], [282, 189], [154, 483], [353, 434]]) pst2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])matrix = cv2.…

atof() - 字符串转double类型

引言 atof() 函数是 C 标准库中用于将字符串(ASCII 字符串)转换为双精度浮点数(double 类型) 的函数,其名称来源于 “ASCII to Float” 的缩写,主要用于处理包含小数或科学计数法的字符串。 一、基本信息 函数原…

完整教程:还在为第三方包 bug 头疼?patch-package 让你轻松打补丁!

完整教程:还在为第三方包 bug 头疼?patch-package 让你轻松打补丁!pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: &q…

Kubernetes(k8s)高可用性集群的构建

1. 规划集群架构控制平面节点(Masters) :至少部署3个控制平面节点以实现高可用性。 工作节点(Workers) :数量根据负载需求决定。 负载均衡器:至少1个,用于分发流量至多个控制平面节点。2. 前期环境准备确保所有…

深入解析:解密llama.cpp:从Prompt到Response的完整技术流程剖析

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

在CentOS环境下升级GCC编译器

CentOS作为一个以稳定性和安全性著称的Linux发行版,它默认包含的软件包和工具通常不是最新版本的,这样做的好处是可以提供一个测试时间更长、更加稳定可靠的系统环境。然而,有时候我们需要用到最新版本的GCC编译器来…

详细介绍:深圳比斯特|电池组PACK自动化生产线厂家概述

详细介绍:深圳比斯特|电池组PACK自动化生产线厂家概述pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&q…

Chapter 4 Shapes and Texts

# [[0. 0. 0 # img = np.zeros(shape=(512, 512)) # [[[0 0 0] img = np.zeros(shape=(512, 512, 3), dtype=np.uint8) # print(img)# Blue 这里还是先 Height,然后是 Width,如果只写255,就是白色了 img[:] = 255,0…