模型思维 - 领域模型的应用与解析

文章目录

  • 引言
  • 模型的核心作用与价值
  • 四大模型类型
  • UML建模工具
    • UML类图的核心价值
    • 类关系深度剖析
    • 企业级建模实践
  • 领域模型(推荐) vs 数据模型(不推荐)
    • 区别联系
    • 错把领域模型当数据模型
      • 错误方案 vs 正确方案对比
      • 正确方案的实现
        • 1. 数据库设计(MySQL 8.0+)
        • 2. 数据对象(DO)定义
        • 3. 领域模型定义
        • 4. 数据转换层实现
        • 5. 业务服务层使用
        • 6. DTO转换示例
      • 架构分层示意图
      • 扩展性
      • 性能优化
      • 关键设计原则
    • 错把数据模型当领域模型
      • JSON字段与垂直表扩展案例详解
        • JSON字段扩展案例:价格规则配置
          • 场景说明
          • 数据模型设计
          • 领域模型设计
          • 转换层实现
        • 垂直表扩展案例:商品扩展属性
          • 场景说明
          • 数据模型设计
          • 领域模型设计
          • 转换层实现
        • 关键对比与选型建议
        • 反模式警示
        • 阿里巴巴中台启示
    • 两种模型各司其职
  • 结语:模型思维的三重境界

在这里插入图片描述


引言

在软件工程中,有两个高阶工作,一个是架构,另一个是建模。如果把写代码比喻成“搬砖”,那么架构和建模就是“设计图纸”了。相比于编码,建模的确是对设计经验和抽象能力要求更高的一种技能。


模型的核心作用与价值

  • 简化与抽象:模型通过剔除无关细节,聚焦问题核心

  • 跨领域通用性:无论是物理实体还是抽象概念,模型均能通过不同形式(数学公式、图形、思维框架)表达系统特性。

  • 动态演进:模型需随认知迭代更新,如同代码重构,需用发展的眼光持续优化。


四大模型类型

  • 物理模型

    • 定义:实物缩小/放大版,如风洞测试中的飞机模型。
    • 应用场景:硬件系统原型验证、建筑可视化设计。
    • 案例:汽车碰撞测试中,物理模型用于模拟真实撞击效果。
  • 数学模型

    • 定义:数学语言描述的系统行为,如线性回归公式。
    • 应用场景:预测分析(如销售预测)、算法设计(如推荐系统)。
    • 案例:电商平台通过 \( Y = aX + b \) 预测用户购买行为,优化库存管理。
  • 概念模型

    • 定义:领域实体抽象,独立于技术实现,如UML类图。
    • 应用场景:领域驱动设计(DDD)、系统架构规划。
    • 案例:在线教育平台中,用“课程-学生-教师”概念模型定义核心业务关系。
  • 思维模型

    • 定义:问题解决框架,如奥卡姆剃刀、金字塔原理。
    • 应用场景:需求分析、技术决策、团队协作。
    • 案例:用“分治思维”拆分微服务架构,降低系统复杂度。

UML建模工具

UML类图的核心价值

  1. 统一语义桥梁

    • 突破语言屏障:Java开发者可通过类图快速理解C#系统设计
    • 跨角色协作:产品经理通过类图理解业务实体关系,DBA依据类图设计数据库表结构
    • 典型案例:Apache Kafka官方文档使用类图展示Broker-Producer-Consumer交互架构
  2. 设计模式可视化
    在这里插入图片描述

    • 观察者模式类图清晰展现主题-观察者解耦机制

类关系深度剖析

  1. 关联关系实战辨析

    关系类型代码特征生命周期典型场景
    普通关联成员变量持有引用独立User-Order(用户拥有订单)
    聚合构造注入(setter/参数传入)独立Car-Engine(汽车包含引擎)
    组合直接实例化(无setter)同步Window-Frame(窗口包含框架)
  2. 依赖关系三种实现方式

    // 方式1:参数依赖
    class Teacher {void teach(Projector proj) {proj.display();}
    }// 方式2:局部变量
    class ReportGenerator {void generate() {PDFExporter exporter = new PDFExporter();exporter.export();}
    }// 方式3:静态调用
    class PaymentService {void process() {Logger.log("Payment processed");}
    }
    
  3. 泛化与接口的黄金法则

    • Liskov替换原则:子类必须完全实现父类约定
      // 错误示范
      class Bird {void fly() {}
      }
      class Penguin extends Bird {} // 企鹅不会飞,违反LSP// 正确方案
      interface Flyable {void fly();
      }
      class Sparrow implements Flyable {}
      class Penguin extends Bird {}  
      

企业级建模实践

  1. 电商领域建模案例

在这里插入图片描述

  • 关键设计点:
    • 订单聚合根管理OrderItem
    • 支付与订单的限界上下文划分
  1. 微服务建模陷阱
    • 过度解耦反模式
      在这里插入图片描述

      • 问题:服务间直接依赖基础设施导致耦合
      • 优化方案:引入适配器层隔离技术细节

类图大师的三重境界

  1. 精确建模:严格遵循UML规范(如IBM Rational统一过程)
  2. 意图建模:突出设计重点(如DDD聚合根加粗显示)
  3. 价值建模:通过类图驱动架构演进(如识别领域事件改进CQRS)

领域模型(推荐) vs 数据模型(不推荐)

区别联系

领域模型关注的是领域知识,是业务领域的核心实体,体现了问题域中的关键概念,以及概念之间的联系。领域模型建模的关键在于模型能否显性化、清晰地表达业务语义,其次才是扩展性。

数据模型关注的是数据存储,所有的业务都离不开数据,以及对数据的CRUD。数据模型建模的决策因素主要是扩展性、性能等非功能属性,无须过多考虑业务语义的表征能力。

根据Robert在《架构整洁之道》一书中的观点:领域模型是核心,数据模型是技术细节。现实情况是,二者都很重要。领域模型和数据模型之所以容易被混淆,是因为两者都强调实体(Entity)和强调关系(Relationship)

者的确有一些共同点,有时领域模型和数据模型会长得很像,甚至会趋同,这很正常。但更多的时候,二者是有区别的。正确的做法应该是有意识地把这两个模型区别开来,分别进行设计,因为它们建模的目标有所不同。

数据模型负责数据存储,其要义是扩展性、灵活性、性能;而领域模型负责业务逻辑的实现,其要义是业务语义显性化的表达,以及充分利用面向对象的特性增强代码的业务表征能力。

在这里插入图片描述

维度领域模型数据模型
核心目标显性化业务语义,封装领域逻辑高效存储数据,支持扩展性和性能优化
设计原则高内聚、低耦合,反映业务概念本质遵循数据库范式(或合理反范式),兼顾查询效率
技术无关性与技术实现解耦,面向业务语言设计依赖存储技术(如关系型/NoSQL数据库)
变化频率随业务需求演进频繁调整相对稳定,避免频繁表结构变更
典型工具UML类图、事件风暴ER图、DDL脚本、JSON Schema

示例对比

  • 订单场景
    • 领域模型Order聚合根包含OrderItemPayment等子实体,封装验价、履约校验逻辑
    • 数据模型orders表使用分库分表策略,order_items表通过JSON存储商品快照

然而在实际情况中,大多数业务系统设计并没有很好地区分二者的关系,我们经常会犯两个错误,一个是错把领域模型当数据模型,另一个是错把数据模型当领域模型


错把领域模型当数据模型

一个报价优化的项目,其中涉及报价规则的问题。这个业务逻辑大概是,对于不同的商品(通过类目、品牌、供应商类型等维度区分),给出不同的价格区间,然后判断商家的报价是应该被自动审核通过(autoApprove),还是应该被自动拦截(autoBlock)。
对于这个规则,领域模型很简单,就是提供价格管控需要的配置数据

在这里插入图片描述

如果按照这个领域模型去设计存储模型,那么需要两张表,分别是price_rule和price_range,一张用来存放价格规则,另一张用来存放价格区间 。

不合理的存储模型

在这里插入图片描述

如果这样设计数据模型,我们就犯了把领域模型当数据模型的错误。这里更合适的做法是只用一张表,把price_range作为一个字段,在price_rule中用一个字段存储, 对于多个价格区间信息,只用一个json字段存储即可

合理的存储模型

 合理的存储模型

这样做的好处显而易见。

  • 首先,维护一张数据库表肯定比维护两张的成本要低。
  • 其次,其数据的扩展性更好。比如,假设有新需求,需要增加一个建议价格(suggest price)区间,如果是两张表,那么需要在price_range中加两个新字段;而如果只用json存储,那么数据模型可以保持不变。

在业务代码中,我们需要把json的数据对象转换成有业务语义的领域对象,这样既可以享受数据模型扩展性带来的便捷性,又不损失领域模型对业务语义显性化带来的代码可读性

在这里插入图片描述


错误方案 vs 正确方案对比

维度错误方案(领域模型直转数据模型)正确方案(领域模型与数据模型解耦)
存储结构2张表(price_rule + price_range)1张表(price_rule含JSON字段)
扩展性新增字段需改表结构新增属性只需改JSON结构
查询复杂度需要JOIN操作单表查询
代码维护性需同时维护两个DAO只需维护一个DAO
领域对象纯度领域对象被数据库外键污染领域对象保持业务语义完整性

正确方案的实现

1. 数据库设计(MySQL 8.0+)
-- 价格规则表
CREATE TABLE price_rule (id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',category_code VARCHAR(50) NOT NULL COMMENT '类目编码',brand_code VARCHAR(50) NOT NULL COMMENT '品牌编码',supplier_type VARCHAR(20) NOT NULL COMMENT '供应商类型',price_ranges JSON NOT NULL COMMENT '价格区间配置',created_time DATETIME DEFAULT CURRENT_TIMESTAMP,updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,INDEX idx_category_brand (category_code, brand_code)
) COMMENT='价格规则表';-- 示例数据
INSERT INTO price_rule (category_code, brand_code, supplier_type, price_ranges) 
VALUES ('ELECTRONICS', 'APPLE', 'OFFICIAL','[{"min": 5000.00,"max": 8000.00,"type": "AUTO_APPROVE","currency": "CNY"},{"min": 8000.01,"max": 10000.00,"type": "MANUAL_REVIEW","currency": "CNY"}]'
);
2. 数据对象(DO)定义
// 持久化对象
public class PriceRuleDO {private Long id;private String categoryCode;private String brandCode;private String supplierType;private String priceRanges; // JSON字符串// 其他字段及getter/setter
}
3. 领域模型定义
// 值对象:价格区间
public class PriceRange {private BigDecimal min;private BigDecimal max;private PriceType type; // 枚举:AUTO_APPROVE/MANUAL_REVIEWprivate Currency currency; // 枚举:CNY/USD// 业务方法:校验价格是否在区间内public boolean contains(BigDecimal price) {return price.compareTo(min) >= 0 && price.compareTo(max) <= 0;}
}// 聚合根:价格规则
public class PriceRule {private Long id;private String categoryCode;private String brandCode;private String supplierType;private List<PriceRange> priceRanges;// 核心业务方法:校验报价public PriceCheckResult checkPrice(BigDecimal price) {return priceRanges.stream().filter(range -> range.contains(price)).findFirst().map(range -> new PriceCheckResult(range.getType())).orElse(PriceCheckResult.BLOCK);}
}
4. 数据转换层实现
// Repository实现
@Repository
public class PriceRuleRepositoryImpl implements PriceRuleRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;private final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic PriceRule findByConditions(String category, String brand) {String sql = "SELECT * FROM price_rule WHERE category_code = ? AND brand_code = ?";PriceRuleDO priceRuleDO = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(PriceRuleDO.class), category, brand);return convertToEntity(priceRuleDO);}private PriceRule convertToEntity(PriceRuleDO priceRuleDO) {try {List<PriceRange> ranges = objectMapper.readValue(priceRuleDO.getPriceRanges(),new TypeReference<List<PriceRange>>(){});return new PriceRule(priceRuleDO.getId(),priceRuleDO.getCategoryCode(),priceRuleDO.getBrandCode(),priceRuleDO.getSupplierType(),ranges);} catch (JsonProcessingException e) {throw new DataConversionException("价格规则数据转换失败", e);}}// 反向转换略...
}
5. 业务服务层使用
@Service
public class PriceCheckService {@Autowiredprivate PriceRuleRepository priceRuleRepository;public PriceCheckResult validatePrice(String category, String brand, BigDecimal price) {PriceRule rule = priceRuleRepository.findByConditions(category, brand);return rule.checkPrice(price);}
}
6. DTO转换示例
// 返回给前端的DTO
public class PriceRuleDTO {private String category;private String brand;private List<PriceRangeDTO> ranges;public static PriceRuleDTO fromEntity(PriceRule rule) {PriceRuleDTO dto = new PriceRuleDTO();dto.setCategory(rule.getCategoryCode());dto.setBrand(rule.getBrandCode());dto.setRanges(rule.getPriceRanges().stream().map(range -> new PriceRangeDTO(range.getMin(),range.getMax(),range.getType().name())).collect(Collectors.toList()));return dto;}
}

架构分层示意图

在这里插入图片描述


扩展性

新增建议价格区间需求时:

  1. 领域模型变更
public class PriceRange {// 增加新字段private BigDecimal suggestPrice;// 新增业务方法public BigDecimal calculatePriceDeviation(BigDecimal offerPrice) {return offerPrice.subtract(suggestPrice).abs();}
}
  1. JSON结构变更
{"min": 5000.00,"max": 8000.00,"type": "AUTO_APPROVE","currency": "CNY","suggest_price": 7500.00
}
  1. 无需修改数据库结构

性能优化

  1. JSON索引优化(MySQL 8.0+)
-- 创建虚拟列并建立索引
ALTER TABLE price_rule 
ADD COLUMN min_price DECIMAL(15,2) GENERATED ALWAYS AS (JSON_EXTRACT(price_ranges, '$[0].min')) STORED,
ADD INDEX idx_min_price (min_price);
  1. 缓存策略
@Cacheable(value = "priceRules", key = "#category + '_' + #brand")
public PriceRule findByConditions(String category, String brand) {// 查询逻辑
}
  1. 异步预热
@Scheduled(fixedRate = 30 * 60 * 1000) // 每30分钟刷新
public void refreshPriceRules() {// 批量加载热数据到缓存
}

关键设计原则

  1. 单一职责原则

    • 领域对象:专注业务逻辑
    • 数据对象:专注存储结构
    • DTO:专注数据传输
  2. 开闭原则

    • 领域模型修改不影响存储层
    • 存储结构变化不影响业务逻辑
  3. 显式语义原则

    • 通过PriceRange.contains()等业务方法明确表达规则
    • 避免在service层出现复杂的价格判断逻辑
  4. 技术适配原则

    • 利用JSON字段处理动态结构
    • 通过虚拟列解决查询性能问题

通过这种设计,我们实现了:

  • 存储层:1张表+JSON字段 => 无限扩展能力
  • 领域层:纯净的PriceRule聚合根 => 显性化业务规则
  • 架构层:清晰的层级边界 => 提升可维护性

当需要增加新的价格维度(如区域定价)时,只需要:

  1. 扩展PriceRange值对象
  2. 调整JSON结构
  3. 更新转换层逻辑

而无需进行耗时的数据库迁移操作,真正实现了领域模型与技术实现的解耦。


错把数据模型当领域模型

数据模型最好是可扩展的,毕竟改动数据库是一个大工程,不管是加字段、减字段,还是加表、删表,都涉及不少的工作量.

说到数据模型的扩展设计经典之作,非阿里巴巴的业务中台莫属。得益于良好的扩展性设计,仅仅其核心的商品、订单、支付、物流4张表,就支撑了阿里巴巴的几十个业务、成千上万个业务场景。

以商品中台为例,它只用了一张auction_extend垂直表,就解决了所有业务商品数据存储扩展性的需求。从理论上来说,这种数据模型可以满足无限的业务扩展需求。

JSON字段也好,垂直表也好,虽然都可以很好地解决数据存储扩展的问题,但我们最好不要把这些扩展当成领域对象来处理,否则代码根本就不是在面向对象编程,而是在面向扩展字段(Features)编程,这就犯了把数据模型当领域模型的错误。更好的做法应该是把数据对象(Data Object)转换成领域对象来处理

JSON字段与垂直表扩展案例详解


JSON字段扩展案例:价格规则配置
场景说明

电商系统需要为不同类目商品配置价格管控规则,每个规则包含多个价格区间(如最低价、最高价、建议价),且区间数量可能动态变化。

数据模型设计
CREATE TABLE price_rule (id BIGINT PRIMARY KEY COMMENT '主键',category_id VARCHAR(20) NOT NULL COMMENT '类目ID',brand_id VARCHAR(20) NOT NULL COMMENT '品牌ID',price_ranges JSON NOT NULL COMMENT '价格区间配置(JSON数组)'
);

示例数据

{"price_ranges": [{"min": 100.00,"max": 500.00,"type": "AUTO_APPROVE"},{"min": 500.00,"max": 1000.00,"type": "MANUAL_REVIEW"}]
}
领域模型设计
// 领域对象:价格规则聚合根
public class PriceRule {private Long id;private String categoryId;private String brandId;private List<PriceRange> priceRanges; // 显式业务对象// 业务方法:校验价格是否合法public PriceCheckResult checkPrice(BigDecimal price) {return priceRanges.stream().filter(range -> range.contains(price)).findFirst().map(range -> new PriceCheckResult(range.getType())).orElse(PriceCheckResult.BLOCK);}
}// 值对象:价格区间
public class PriceRange {private BigDecimal min;private BigDecimal max;private PriceType type; // 枚举:AUTO_APPROVE/MANUAL_REVIEW
}
转换层实现
// Repository层转换逻辑
public class PriceRuleRepository {public PriceRule findById(Long id) {PriceRuleDO priceRuleDO = jdbcTemplate.queryForObject(...);return convertToEntity(priceRuleDO);}private PriceRule convertToEntity(PriceRuleDO priceRuleDO) {List<PriceRange> ranges = objectMapper.readValue(priceRuleDO.getPriceRanges(), new TypeReference<List<PriceRange>>(){});return new PriceRule(priceRuleDO.getId(),priceRuleDO.getCategoryId(),priceRuleDO.getBrandId(),ranges);}
}

优势

  • 扩展性:新增价格类型时无需修改表结构
  • 业务语义清晰PriceRange对象封装校验逻辑
  • 技术解耦:JSON解析完全隐藏在Repository层

垂直表扩展案例:商品扩展属性
场景说明

商品系统需要支持不同类目商品的扩展属性(如图书类商品需要作者、出版社,电子类商品需要型号、保修期)。

数据模型设计
-- 商品主表
CREATE TABLE product (id BIGINT PRIMARY KEY COMMENT '主键',sku VARCHAR(50) NOT NULL COMMENT '商品编码',category VARCHAR(20) NOT NULL COMMENT '类目'
);-- 商品扩展表(垂直表)
CREATE TABLE product_extend (product_id BIGINT COMMENT '商品ID',extend_key VARCHAR(50) COMMENT '扩展键',extend_value VARCHAR(500) COMMENT '扩展值',PRIMARY KEY (product_id, extend_key)
);

示例数据

product_idextend_keyextend_value
1001authorJ.K. Rowling
1001publisherBloomsbury
2002modeliPhone 15
2002warranty2 years
领域模型设计
// 领域对象:商品聚合根
public class Product {private Long id;private String sku;private String category;private ProductDetail detail; // 显式业务对象
}// 值对象:商品详情(根据类目动态扩展)
public class ProductDetail {// 图书类属性private String author;private String publisher;// 电子类属性private String model;private String warranty;// 通用方法:校验类目与属性匹配public void validateCategory(String category) {if ("BOOK".equals(category) && author == null) {throw new BusinessException("图书必须包含作者信息");}}
}
转换层实现
// 防腐层转换逻辑
public class ProductAdapter {public Product convert(ProductDO productDO, List<ProductExtendDO> extendDOs) {ProductDetail detail = new ProductDetail();extendDOs.forEach(extend -> {switch (extend.getKey()) {case "author": detail.setAuthor(extend.getValue()); break;case "publisher": detail.setPublisher(extend.getValue()); break;case "model": detail.setModel(extend.getValue()); break;case "warranty": detail.setWarranty(extend.getValue()); break;}});return new Product(productDO.getId(),productDO.getSku(),productDO.getCategory(),detail);}
}

优势

  • 无限扩展:新增属性只需插入新记录
  • 查询优化:可通过索引快速定位特定扩展属性
  • 领域隔离ProductDetail对象强制业务校验逻辑

关键对比与选型建议
维度JSON字段垂直表
存储效率高(单字段存储)低(多行存储)
查询性能差(无法走索引)优(可对key/value建索引)
扩展成本零成本(无需DDL变更)低(仅插入新记录)
适用场景配置类数据(如规则、参数)需要检索的扩展属性(如商品特征)
领域适配需反序列化为领域对象需键值对到领域属性的映射

反模式警示

错误示例:在业务层直接操作扩展字段

// 错误!领域层直接处理技术细节
public class ProductService {public void updateProduct(Long productId, Map<String, String> features) {productExtendDao.batchUpdate(features); // 直接操作扩展表}
}

正确实践:通过防腐层隔离技术细节

public class ProductService {public void updateProduct(Product product) {product.validate(); // 业务校验List<ProductExtendDO> extendDOs = convertToExtendDOs(product);productExtendDao.batchUpdate(extendDOs); }private List<ProductExtendDO> convertToExtendDOs(Product product) {// 将领域对象转换为数据对象}
}

阿里巴巴中台启示

auction_extend表设计精髓

CREATE TABLE auction_extend (auction_id BIGINT COMMENT '商品ID',extend_key VARCHAR(64) COMMENT '扩展键',extend_value VARCHAR(4096) COMMENT '扩展值',PRIMARY KEY (auction_id, extend_key)
) COMMENT='商品扩展表';

配套领域模型设计

// 商品领域服务
public class AuctionService {// 根据业务场景动态组装领域对象public AuctionDetail getAuctionDetail(Long auctionId) {AuctionDO auctionDO = auctionDao.findById(auctionId);List<AuctionExtendDO> extendDOs = auctionExtendDao.findByAuctionId(auctionId);return AuctionDetailAssembler.assemble(auctionDO, extendDOs);}
}

经验总结

  • 物理存储与逻辑模型分离:扩展表只关心数据存储,不参与业务逻辑
  • 双向转换机制
    • 写入时:将领域对象拆解为auction主表+auction_extend扩展表
    • 读取时:通过Assembler将多表数据组合为完整领域对象
  • 缓存优化:对高频访问的扩展属性建立二级缓存(如作者、型号等)

通过这两个案例可以看出:优秀的数据模型扩展方案必须与领域模型解耦。JSON字段和垂直表解决的是存储层的扩展问题,而领域模型需要保持对业务语义的精确表达。二者的协作需要通过明确的转换层来实现,这正是DDD中"防腐层"思想的精髓所在。


两种模型各司其职

应该是把领域模型和数据模型区别开来,让它们各司其职,从而使应用系统架构更合理。
领域模型是面向领域对象的,要尽量具体,尽量语义明确,显性化地表达业务语义是其首要任务,扩展性是其次;数据模型是面向数据存储的,要尽量可扩展。

在具体落地时,我们可以采用COLA的架构思想,使用gateway作为数据对象(Data Object, DO)和领域对象(Entity)之间的转义网关,如图所示。其中,gateway除了起到转义的作用,还起到了防腐解耦的作用,解除了业务代码对底层数据(DO、DTO等)的直接依赖,从而提升系统的可维护性。

领域模型和数据模型具体落地

在这里插入图片描述


此外,教科书上告诉我们,在做关系数据库设计时要满足3NF(第三范式),然而在实际工作中,我们经常会因为性能、扩展性的原因故意打破这个原则。比如,通过数据冗余提升访问性能,通过元数据、垂直表、扩展字段提升表的扩展性

不同的业务场景对数据扩展的诉求也不一样,像price_rule这种简单的配置数据扩展,json就能胜任。更复杂的,用auction_extend这种垂直表也是不错的选择。

看到这里,可能会问:这样做,数据是可扩展了,可数据查询怎么解决呢?总不能用join表或者like吧。实际上,

  • 对一些配置类的数据或者数据量不大的数据,我们完全可以用like。
  • 然而,对于海量数据,当然不能用like,不过这个问题很容易通过读写分离、构建搜索(Search)的办法解决,如图所示。

使用搜索解决读写性能问题

在这里插入图片描述

领域模型和数据模型有明显区别,领域模型关心的是业务概念,其要义是显性化地表达业务语义;数据模型关心的是数据存储,其核心是数据访问的性能、数据的扩展性等非功能属性。


结语:模型思维的三重境界

  1. 见山是山:严格遵循现有模型(如教科书中的设计模式);
  2. 见山不是山:根据上下文裁剪模型(如微服务中的CQRS变形);
  3. 见山仍是山:超越模型形式,直击问题本质(如用简单事件溯源替代复杂ESB)。

掌握模型思维,实则是培养“以简驭繁”的能力——正如埃隆·马斯克推崇的第一性原理,穿透表象,直抵核心矛盾。在软件工程的复杂迷局中,优秀的模型如同指南针,在混沌中开辟清晰路径。

在这里插入图片描述

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

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

相关文章

基于GWO灰狼优化的WSN网络最优节点部署算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 无线传感器网络&#xff08;Wireless Sensor Network, WSN&#xff09;由大量分布式传感器节点组成&#xff0c;用于监测物理或环境状况。节点部署是 WSN 的关键问…

产品概念的提出

产品概念的提出 一个产品或者一个产品概念idea是怎么想到的呢&#xff1f;很多情况下它其实来自生活中的一些不爽、不满意、想吐槽&#xff0c;凡是用户抱怨的事情就是用户的强烈刚需需求是我们要去做的事情。当有了一个想法时需要弄清楚一下几个问题&#xff1a; 核心用户事…

3.Docker常用命令

1.Docker启动类命令 1.启动Docker systemctl start docker 2.停止Docker systemctl stop docker 3.重启Docker systemctl restart docker 4.查看Docker状态 systemctl status docker 5.设置开机自启(执行此命令后每次Linux重启后将自启动Docker) systemctl enable do…

交互编程工具之——Jupyter

Jupyter 是什么&#xff1f; Jupyter 是一个开源的交互式编程和数据分析工具&#xff0c;广泛应用于数据科学、机器学习、教育和研究领域。其核心是 Jupyter Notebook&#xff08;现升级为 JupyterLab&#xff09;&#xff0c;允许用户在一个基于浏览器的界面中编写代码、运行…

使用 AIStor 和 OpenSearch 增强搜索功能

在这篇文章中&#xff0c;我们将探讨搜索&#xff0c;特别是 OpenSearch 如何帮助我们识别模式或查看不断增长的数据中的趋势。例如&#xff0c;如果您正在查看运营数据&#xff0c;如果您的服务似乎是随机的&#xff0c;那么您需要尽可能回溯以识别模式并找出原因。这不仅适用…

java基础学习

java基础 面向对象三大特性 特性&#xff1a;封装、继承、多态&#xff1b; 封装&#xff1a;对抽象的事物抽象化成一个对象&#xff0c;并对其对象的属性私有化&#xff0c;同时提供一些能被外界访问属性的方法&#xff1b; 继承&#xff1a;子类扩展新的数据域或功能&#…

MySQL | MySQL库、表的基本操作01

MySQL库、表的基本操作01 一、库操作1.1 查看数据库1.2 创建数据库1.3 选择数据库1.4 查看创建数据库的SQL语句1.5 修改数据库1.6 删除数据库 二、表操作2.1 创建数据表2.2 查看表2.3 查看表结构2.4 查看创建数据库的SQL语句2.5 修改表2.6 删除表 ⚠️MySQL版本 8.0 一、库操作…

设备唯一ID获取,支持安卓/iOS/鸿蒙Next(uni-device-id)UTS插件

设备唯一ID获取 支持安卓/iOS/鸿蒙(uni-device-id)UTS插件 介绍 获取设备唯一ID、设备唯一标识&#xff0c;支持安卓&#xff08;AndroidId/OAID/IMEI/MEID/MacAddress/Serial/UUID/设备基础信息&#xff09;,iOS&#xff08;Identifier/UUID&#xff09;&#xff0c;鸿蒙&am…

正点原子[第三期]Arm(iMX6U)Linux系统移植和根文件系统构建-5.3 xxx_defconfig过程

前言&#xff1a; 本文是根据哔哩哔哩网站上“arm(iMX6U)Linux系统移植和根文件系统构键篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。 引用&#xff1a; …

力扣热题 100:哈希专题三道题详细解析(JAVA)

文章目录 一、两数之和1. 题目描述2. 示例3. 解题思路4. 代码实现&#xff08;Java&#xff09;5. 复杂度分析 二、字母异位词分组1. 题目描述2. 示例3. 解题思路4. 代码实现&#xff08;Java&#xff09;5. 复杂度分析 三、最长连续序列1. 题目描述2. 示例3. 解题思路4. 代码实…

嵌入式八股文(五)硬件电路篇

一、名词概念 1. 整流和逆变 &#xff08;1&#xff09;整流&#xff1a;整流是将交流电&#xff08;AC&#xff09;转变为直流电&#xff08;DC&#xff09;。常见的整流电路包括单向整流&#xff08;二极管&#xff09;、桥式整流等。 半波整流&#xff1a;只使用交流电的正…

AI2-THOR环境下实现机器人导航、物体定位与抓取

1. 依赖安装 pip install ai2thor pip install numpy pillow opencv-python2. 验证安装 # 运行测试脚本验证安装 test_thor.py from ai2thor.controller import Controller controller Controller(scene"FloorPlan1") controller.step(action"MoveAhead"…

Nginx(详解以及如何使用)

目录 1. 什么是Nginx&#xff1f; 2. 为什么使用nginx? 3. 安装nginx 3.1?安装nginx的依赖插件 3.2 下载nginx ?3.3?创建一个目录作为nginx的安装路径 ?3.4?解压 ?3.5?进入解压后的目录 3.6?指定nginx的安装路径 ?3.7?编译和安装nginx 3.8 启动nginx ?…

【自动化脚本工具】Hammerspoon (Mac)

目录 1. 介绍Hammerspoon 1. 介绍Hammerspoon This is a tool for powerful automation of OS X. At its core, Hammerspoon is just a bridge between the operating system and a Lua scripting engine. What gives Hammerspoon its power is a set of extensions that expo…

2025 PHP授权系统网站源码

2025 PHP授权系统网站源码 安装教程&#xff1a; PHP7.0以上 先上传源码到服务器&#xff0c;然后再配置伪静态&#xff0c; 访问域名根据操作完成安装&#xff0c; 然后配置伪静态规则。 Ngix伪静态规则&#xff1a; location / { if (!-e $request_filename) { rewrite …

Javascript网页设计案例:通过PDFLib实现一款PDF分割工具,分割方式自定义-完整源代码,开箱即用

功能预览 一、工具简介 PDF 分割工具支持以下核心功能: 拖放或上传 PDF 文件:用户可以通过拖放或点击上传 PDF 文件。两种分割模式: 指定范围:用户可以指定起始页和结束页,提取特定范围的内容。固定间距:用户可以设置间隔页数(例如每 5 页分割一次),工具会自动完成分…

基于SpringBoot的民宿管理系统的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

调用click.getchar()时Windows PyCharm无法模拟键盘输入

文章目录 问题描述解决方案参考文献 问题描述 调用 click.getchar() 时&#xff0c;Windows PyCharm 无法模拟键盘输入 解决方案 Run → Edit Configurations… → Modify options → Emulate terminal in output console 参考文献 Terminal emulator | PyCharm Documentati…

hugging face---transformers包

一、前言 不同于计算机视觉的百花齐放&#xff0c;不同网络适用不同情况&#xff0c;NLP则由Transformer一统天下。transformer是2017年提出的一种基于自注意力机制的神经网络架构&#xff0c;transformers库是hugging face社区创造的一个py库&#xff0c;通过该库可以实现统一…

AI大模型学习(四): LangChain(三)

Langchain构建代理 语言模型本身无法执行动作,他们只能输出文本,代理是使用大型语言模型(LLM)作为推理引擎来确定要执行的操作以及这些操作的输入应该是什么,然后这些操作的结果可以反馈到代理中,代理将决定是否需要更多的操作,或者是否可以结束 例如:我们想要查询现在北京的…