首页/新闻资讯/正文详情

【软件架构方法论(9)】领域模型:如何通过领域模型,提高系统的可扩展性?

发布时间:2026/11/3 1:48:17 来源:云帆数科 栏目:资讯中心
【软件架构方法论(9)】领域模型:如何通过领域模型,提高系统的可扩展性?
文章目录一、领域模型决定功能扩展的范围案例人事系统的历史记录问题案例电商系统的分类层次问题二、好的领域模型如何支持扩展将关系、角色抽象1、可扩展的任务依赖关系设计关系抽象2、可扩展的角色和分配设计角色抽象三、如何设计可扩展的领域模型1、考虑当前功能和潜在功能2、使用抽象和组合而不是硬编码3、迭代优化而不是一次到位四、总结领域模型是系统扩展性的基础核心观点领域模型就像房子的承重墙它决定了系统能扩展到哪里不能扩展到哪里。好的领域模型让系统容易扩展差的领域模型让系统难以扩展。因此建模时要考虑未来的功能需求而不仅仅是当前的功能需求。很多系统在初期运行良好但随着业务需求的变化扩展起来越来越困难。比如人事系统最初只能记录员工当前职位后来需要查看员工历史履历却发现数据库设计不支持电商系统最初只支持两级分类后来需要支持多级分类却发现模型设计不支持。这些问题的根源往往不在代码实现而在领域模型设计。一、领域模型决定功能扩展的范围领域模型是对业务世界的抽象任何抽象都意味着有意的省略。你抽象了什么系统就能支持什么你没抽象什么系统就很难支持什么。就像拍照和X光片的区别拍照只能看到表面X光片能看到内部结构。领域模型就是系统的X光片它决定了系统功能的骨骼结构。如果骨骼结构不支持某个功能即使表面代码写得再好也很难实现。案例人事系统的历史记录问题最初的人事系统领域模型很简单公司和员工是一对多的关系一个公司有多个员工员工的姓名、性别、地址、职位、部门、薪水直接作为员工的属性。这个模型支持查看员工当前信息这个功能完全没问题。数据库设计也很简单一个Company表一个Employee表Employee表通过外键关联Company表。但后来业务需求变了HR经理想要查看员工的完整履历包括在不同时间段的职位、部门、薪水变化。比如一个员工可能先做软件工程师后来升职为高级软件工程师再后来调岗到项目经理每次变化都要记录时间段。这时候问题就来了原来的模型只记录了当前信息没有记录历史信息。要支持新功能必须修改模型。如果只是修改应用层代码会发现根本改不动。因为数据库表结构不支持Employee表只有当前的职位、部门、薪水字段没有历史记录业务层的接口也不支持Employee类只有getJobTitle()方法没有getJobHistory()方法。必须重新设计领域模型升级后的模型把职位、“部门”、薪水从员工的属性关键点变成雇佣关系的属性而雇佣关系记录了时间段。这样一个员工可以有多条雇佣记录每条记录对应一个时间段开始时间、结束时间就能支持历史履历查询了。数据库设计需要增加一个Employment表记录employee_id、company_id、时间段、职位、部门、薪水。这样查询员工履历时只需要查询Employment表按时间段排序即可。这个案例说明领域模型决定了系统能支持哪些功能不能支持哪些功能。如果模型设计时没有考虑历史记录系统就很难支持历史查询功能。案例电商系统的分类层次问题电商系统最初的需求是支持两级分类大类和小类。比如电脑办公是大类笔记本是小类。领域模型设计成Category大类和Subcategory小类是两个独立的类Category包含多个Subcategory。数据库设计也很简单一个category表一个subcategory表subcategory表通过外键关联category表。这个模型支持两级分类完全没问题。但后来业务需求变了需要支持多级分类。比如美妆 男士专区 男士剃须用品 刀架/刀片这是四级分类。原来的模型就支持不了了因为Subcategory不能再包含子分类。要支持多级分类必须修改模型让Category可以递归包含自身一个Category可以有一个父Categorysuper_category也可以有多个子Category。这样分类层次就可以是1到N层灵活多了。数据库设计也需要修改只需要一个category表增加一个super_category_id字段外键关联category.id通过这个字段实现递归关系更进一步的如果还需要支持一个商品属于多个分类比如一本书既属于红色读物又属于非虚构文学还属于小说模型还需要再次升级Category和Commodity之间从一对多关系变成多对多关系。数据库设计需要增加一个commodity_category中间表记录commodity_id和category_id的对应关系。这个案例说明领域模型的设计要考虑未来可能的功能需求而不仅仅是当前的功能需求。如果只考虑当前需求模型可能会限制未来的扩展。二、好的领域模型如何支持扩展将关系、角色抽象好的领域模型能够在不修改核心结构的情况下支持新功能的添加。这就像房子的承重墙设计得好可以在不拆墙的情况下改变房间的布局。1、可扩展的任务依赖关系设计关系抽象在项目管理系统中最初只需要支持结束-开始关系一个任务必须等另一个任务结束后才能开始。比如洗锅任务结束后炒菜任务才能开始。如果模型设计成Task直接有一个preTask属性前置任务这个设计支持结束-开始关系没问题。接口可能是这样的Task::SetPreTask(Task pre_task)这个操作可以定义在Task类中。但如果未来需要支持其他关系呢比如开始-开始关系清洁地板开始后刷油漆就可以开始两个任务可以同时开始开始-结束关系哨兵上岗开始后哨兵下岗才能结束第二个任务必须等第一个任务开始后才能结束结束-结束关系批准整个设计结束后制定下一步计划才能结束两个任务必须同时结束如果模型只支持前置任务这种简单关系要支持这些复杂关系就必须修改模型Task类需要增加多个属性来记录不同类型的关系修改接口原来的Task::SetPreTask()接口不够用需要改成TaskUtility::SetTaskDependingRelation(Task task_a, Task task_b, TaskDependingRelation dr)而且这个操作不适合定义在Task类中修改数据库数据库Schema需要改变封装数据库Schema的代码如DAO也需要改变但如果模型设计成有一个任务关系类TaskRelationship它连接两个任务task_a和task_b并记录关系类型结束-开始、开始-开始、开始-结束、结束-结束那么要支持新关系只需要添加新的关系类型枚举值不需要修改核心结构。这样接口可以设计成TaskUtility::SetTaskDependingRelation(Task task_a, Task task_b, TaskDependingRelationType type)关系类型可以扩展但接口结构不需要改变。这个设计的关键在于把关系本身抽象成一个概念而不是把关系硬编码在任务中。这样关系类型就可以扩展而任务和关系之间的核心结构不需要改变。2、可扩展的角色和分配设计角色抽象在项目管理系统中不同企业对角色的定义可能不同有些企业角色很细项目经理、过程经理、质量经理等有些企业角色很粗就是项目成员。系统要支持这两种情况就需要角色定义可以扩展。如果模型设计成角色是固定的几个类项目经理、过程经理等要添加新角色就必须修改代码。但如果模型设计成有一个角色基类具体角色可以继承扩展那么要添加新角色只需要定义新的角色类不需要修改核心代码。更进一步如果系统不仅要支持把任务分配给个人还要支持把任务分配给团队或部门模型也需要扩展。如果模型设计成任务只能分配给个人Person要支持团队分配就必须修改模型Task类需要增加teamAssignment属性修改接口原来的Task::AssignTo(Person person)接口不够用需要增加Task::AssignToTeam(Team team)方法修改数据库需要增加team_assignment相关字段但如果模型设计成任务分配给Party当事人而Party可以是个人Individual或团队Team那么要支持团队分配只需要添加团队类Team继承Party任务分配的核心逻辑不需要改变因为都是分配给Party接口可以设计成Task::AssignTo(Party party)无论是个人还是团队都用同一个接口这样分配对象可以扩展但分配逻辑不需要改变。这就是使用抽象和继承的好处。这个设计的关键在于使用抽象和继承让具体类型可以扩展而核心逻辑不需要改变。三、如何设计可扩展的领域模型设计可扩展的领域模型关键在于功能决定如何建模模型决定功能扩展。1、考虑当前功能和潜在功能建模时不仅要考虑当前需要的功能还要考虑未来可能需要的功能。这不是要你预测所有未来需求而是要你识别那些很可能出现的需求。比如在人事系统中查看历史履历是一个很可能出现的需求因为员工会升职、调岗、离职、再入职。在电商系统中多级分类和商品多分类也是很可能出现的需求因为业务会发展。识别这些很可能出现的需求在建模时提前考虑可以让模型更容易扩展。就像盖房子时即使现在只住一层但如果很可能要加层地基就要打深一点。2、使用抽象和组合而不是硬编码好的领域模型使用抽象和组合来组织概念而不是把具体关系硬编码在类中。比如任务依赖关系不要设计成Task有一个preTask属性而要设计成Task和Task通过TaskRelationship连接。这样关系类型可以扩展关系属性比如延迟时间也可以扩展。再比如资源分配不要设计成Task分配给Person而要设计成Task分配给PartyParty可以是Person或Team。这样分配对象可以扩展分配逻辑不需要改变。3、迭代优化而不是一次到位领域模型不是一次设计就能完美的而是随着对业务理解的深入不断迭代优化的。就像项目管理系统的案例最初的理解可能是项目和任务是一对多后来发现多个项目可以共享任务模型就需要调整。最初可能只考虑任务分配给个人后来发现任务可能分配给团队模型就需要扩展。这个过程是正常的也是必要的。关键是每次迭代时要考虑扩展性而不是只考虑当前需求。如果每次迭代都只考虑当前需求模型会越来越难以扩展。四、总结领域模型是系统扩展性的基础领域模型决定了系统能扩展到哪里不能扩展到哪里。就像房子的承重墙决定了能盖多高能改多大一样。因此设计领域模型时要内外兼修既要满足当前功能需求也要考虑未来扩展需求。就像《高效能人士的七个习惯》中说的由内而外的思维好的软件扩展性需要由内而外的领域模型设计。更重要的是领域模型的扩展性不是靠预测所有未来需求来实现的而是靠识别很可能出现的需求和使用抽象和组合来实现的。这样即使未来需求超出预期模型也能相对容易地调整和扩展。最终一个好的领域模型应该让系统在支持新功能时只需要添加代码而不需要修改核心代码。这种扩展性是系统长期维护和演化的基础。

相关推荐

【软件架构设计方法论(4)】需求分析:从愿景到规格的完整路径
【软件架构设计方法论(4)】需求分析:从愿景到规格的完整路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:48:17

【效率突破】Qwen2.5-7B-Instruct部署全攻略:五大工具链协同实现推理性能3倍跃升
【效率突破】Qwen2.5-7B-Instruct部署全攻略:五大工具链协同实现推理性能3倍跃升

【效率突破】Qwen2.5-7B-Instruct部署全攻略:五大工具链协同实现推理性能3倍跃升 在大语言模型(LLM)落地企业级应用的过程中,Qwen2.5-7B-Instruct凭借其出色的平衡性能成为热门选择。然而,开发者在实际部署时常常面临三… · 2026/11/3 1:48:17

300亿参数开源模型震撼发布:Step-Video-T2V引领AI视频生成新革命
300亿参数开源模型震撼发布:Step-Video-T2V引领AI视频生成新革命

300亿参数开源模型震撼发布:Step-Video-T2V引领AI视频生成新革命 2025年2月,阶跃星辰(StepFun)发布了一款具有里程碑意义的文本生成视频模型——Step-Video-T2V。这款拥有300亿参数的开源模型,凭借204帧的超长视频时长… · 2026/11/3 1:48:17

智能编程提醒系统:提升开发者效率的IDE集成方案
智能编程提醒系统:提升开发者效率的IDE集成方案

1. 项目背景与核心价值最近在整理个人工作流时,发现一个高频痛点:编程过程中经常因为沉浸式coding而忘记重要事项。这种状态我们开发者都懂——当思路正流畅时,谁都不愿被打断,但后果可能就是错过会议、忘记吃药、耽误接娃。于是动… · 2026/11/3 3:23:33

Oracle Data Guard归档间隙检测与处理全攻略
Oracle Data Guard归档间隙检测与处理全攻略

1. ADG归档间隙问题概述在Oracle Data Guard环境中,归档间隙(Archive Gap)是指主库生成的归档日志未能完整传输到备库的情况。这种情况会导致备库无法与主库保持同步,严重时可能造成数据不一致。归档间隙通常表现为备库应用日志时… · 2026/11/3 3:23:33

前缀和算法解析与LeetCode 303实战
前缀和算法解析与LeetCode 303实战

1. 前缀和算法基础概念前缀和(Prefix Sum)是一种通过对原始数组进行预处理来优化区间查询操作的算法技巧。它的核心思想是预先计算并存储数组从起始位置到每个位置的累加和,从而将后续的区间求和操作转化为简单的减法运算。1.1 前缀和的定义与… · 2026/11/3 3:23:33

编程农场:游戏化工具提升开发者效率
编程农场:游戏化工具提升开发者效率

1. 项目概述:编程农场是什么?第一次听到"编程农场"这个概念时,我脑海中浮现的是程序员们戴着草帽在键盘上"耕作"的有趣画面。但实际接触后发现,这是一个将编程学习与时间管理相结合的创新工具。简单来说&… · 2026/11/3 3:23:33

Vue2 v-for循环渲染原理与性能优化实战
Vue2 v-for循环渲染原理与性能优化实战

1. Vue2循环渲染核心机制解析在Vue2项目开发中,v-for指令是处理列表渲染的瑞士军刀。这个看似简单的语法糖背后,隐藏着Vue响应式系统的精妙设计。我曾在电商后台管理系统开发中,遇到过2000商品列表的渲染性能问题,最终通过深入理解… · 2026/11/3 3:23:33

Vue3+SpringBoot项目Docker容器化部署实战指南
Vue3+SpringBoot项目Docker容器化部署实战指南

1. 项目概述最近在技术社区看到不少开发者对Vue3SpringBoot前后端分离项目的容器化部署存在困惑。作为一个经历过多次完整项目部署的老兵,我想分享下从零开始的Docker化实战经验。这次我们先聚焦环境搭建和数据库容器化这两个基础但关键的环节。这个教程适合已经掌握… · 2026/11/3 3:22:33

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码