当前位置: 首页 > news >正文

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

文章目录

    • 一、领域模型决定功能扩展的范围
      • 案例:人事系统的历史记录问题
      • 案例:电商系统的分类层次问题
    • 二、好的领域模型如何支持扩展?将关系、角色抽象!
      • 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可以有一个父Category(super_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分配给Party,Party可以是Person或Team"。这样,分配对象可以扩展,分配逻辑不需要改变。
 

3、迭代优化,而不是一次到位

领域模型不是一次设计就能完美的,而是随着对业务理解的深入,不断迭代优化的。

就像项目管理系统的案例,最初的理解可能是"项目和任务是一对多",后来发现"多个项目可以共享任务",模型就需要调整。最初可能只考虑"任务分配给个人",后来发现"任务可能分配给团队",模型就需要扩展。

这个过程是正常的,也是必要的。关键是:每次迭代时,要考虑扩展性,而不是只考虑当前需求。如果每次迭代都只考虑当前需求,模型会越来越难以扩展。
 

四、总结:领域模型是系统扩展性的基础

领域模型决定了系统能扩展到哪里,不能扩展到哪里。就像房子的承重墙决定了能盖多高,能改多大一样。

因此,设计领域模型时,要"内外兼修":既要满足当前功能需求,也要考虑未来扩展需求。就像《高效能人士的七个习惯》中说的"由内而外"的思维,好的软件扩展性,需要"由内而外"的领域模型设计。

更重要的是,领域模型的扩展性,不是靠"预测所有未来需求"来实现的,而是靠"识别很可能出现的需求"和"使用抽象和组合"来实现的。这样,即使未来需求超出预期,模型也能相对容易地调整和扩展。

最终,一个好的领域模型,应该让系统在支持新功能时,只需要"添加"代码,而不需要"修改"核心代码。这种扩展性,是系统长期维护和演化的基础。

 

http://www.dtcms.com/a/597542.html

相关文章:

  • 基于Spring Security +JWT+Redis实现登录认证的流程
  • 深圳做网站最好的公司什么是企业形象设计
  • 【C++基础与提高】第六章:函数——代码复用的艺术
  • 【学习记录】ros2中处理livox_ros_driver1格式的msg
  • 仙游县住房和城乡建设局网站wordpress编辑角色无法上传图片
  • 邮箱类网站模板智联招聘官方网
  • 台湾旺久PL27A1芯片参数|USB3.0对拷线方案芯片|PL27A1对拷线芯片规格书
  • 开源企业建站系统哪个好广州网站建设q479185700棒
  • 网站开发制作流程中国招商网
  • 复杂网络入门到精通5:网络动力学
  • 【论文阅读】PhotoBot: Reference-Guided Interactive Photography via Natural Language
  • Alpha稳定分布概率密度函数的MATLAB实现
  • 国内做网站好的公司淄博做网站小程序的公司
  • Python处理 “列表套字典” 结构JSON数据的三种方式对比
  • 广州市官网网站建设公司详情页模板尺寸
  • 深度学习_神经网络_损失函数基础
  • Centos7.9创建新用户,授权远程登录,禁用root远程登录
  • 柔性软风管-连续测量十分便利
  • 手机网站优化排名首页浏阳seo
  • 辽宁住房与城乡建设厅网站网站单子
  • python类的内置函数
  • chrome的Network上经常看不到网络请求,解决方案
  • 复现------
  • 专业网站建设制作多少钱江门网站建设技术托管
  • 基于MATLAB的POD-DMD联合分析实现方案
  • saas 平台架构做网站简述建设一个网站的具体步骤6
  • 均安公司网站建设wordpress tag做专题
  • 邯郸手机网站开发价格怎样找做淘宝客的网站
  • Linux系统编程——进程通信之无名管道
  • 基于springboot高校办公室行政事务管理系统【带源码和文档】