本文是技术人面试系列领域模型落地篇,也是面试题系列的完结篇,感谢大家对本系列文章的支持~面试中关于领域模型落地都有必要了解哪些内容?一文带你仔细地了解,欢迎收藏!
每个微服务中的代码变化都是同一类原因。因这类原因而需要变更的代码都在这个微服务中,与其他微服务无关,那么就可以将代码修改的范围缩小到这个微服务内。把这个微服务修改好了,独立修改、独立发布,该需求就实现了。这样,微服务的优势才能发挥出来。
就是说在微服务实现自身业务的过程中,若需要执行的某些过程不是自己的职责,就应当将这些过程交给其他微服务去实现,你只需要对它的接口进行调用。这样,微服务之间的调用就实现了解耦。
领域建模就是将一个系统区别划分成了多个子域,每个子域都是一个独立的业务场景,每个子域的边界就是“限界上下文”。该业务场景会涉及许多领域对象,但分析建模始终需要围绕着业务场景的上下文进行。
领域事件通知机制最有效的方式是通过消息队列,实现领域事件在微服务间的通知。
“核心通讯录”微服务只负责发送变更消息到消息队列,不管谁会接收并处理这些消息;
基于充血模型与贫血模型设计各个微服务的业务领域层(Service、Entity、Value)
通过合理的微服务设计,尽量让每次的需求变更都交给某个小团队独立完成,让需求变更落到某个微服务上进行变更。唯有这样,每次变更只需独立地修改这个微服务,独立打包、独立升级,新需求独立实现,才能发挥微服务的优势。
数据隔离:数据库中用户个人信息表的读写只有通讯录微服务。当其他微服务需要读写用户个人信息时,就不能直接读取用户个人信息表,而是通过 API 接口去调用通讯录微服务。
接口复用:因此,当多个团队向你提需求时,必须要对这些接口进行规划,通过复用尽可能少的接口满足他们的需求;当有新的接口提出时,要尽量通过现有接口解决问题。
向前兼容:当调用方需要接口变更时怎么办?变更现有接口应当尽可能向前兼容,即接口的名称与参数都不变,只是在内部增加新的功能。宁愿增加一个新的接口也建议还是不要去变更原有的接口。
本地调用:在访客申请微服务的本地,增加一个查询用户Service的 feign 接口。这样,访客申请Service就像本地调用一样调用查询用户Service,再通过 feign 接口实现远程调用。这种防腐层的设计,可以隔离当前微服务以外的其他微服务拆分变更导致的接口的失效的影响。
微服务中通讯录服务与健康码服务分别对应的用户库与权限库,它们的共同特点是数据量小但频繁读取,能选用小型的 MySQL 数据库并在前面架设 Redis 来提高查询性能;
微服务中访客通行与生活缴费分别对应的通行记录库、订单库,其特点是数据量大并且高并发写,选用一个数据库显然扛不住这样的压力,因此能选用了 TiDB 这样的 NewSQL 数据库进行分布式存储,将数据压力分散到多个数据节点中,从而解决 I/O 瓶颈;
微服务中数据分析与通讯录查询这样的查询分析业务,则选用 NoSQL 数据库或大数据平台,通过读写分离将生产库上的数据同步过来进行分布式存储,然后宽表一系列的预处理,应对海量历史数据的决策分析与秒级查询。( NoSQL 为空的字段是不占用空间的,因此字段再多都不影响查询性能)
贫血模型、充血模型、策略模式、装饰者模式只是DDD实现的方式,而DDD的真谛是领域建模。
做事不能仅凭一腔热血,一定要符合自然规律。其实软件的设计开发过程也是这样。对业务理解不深刻全局架构设计往往是过度设计,这时候应该抓主要流程,开始领域建模。
接着,每次添加新功能的时候,一方面要满足当前的需求,另一方面业务相关的领域建模设计刚刚满足需求,从而使设计最简化、代码最少。
这样的设计过程叫小步快跑。采用小步快跑的设计方法,一开始不用思考那么多问题,从简单问题开始慢慢地深入。领域模型就像小树一样一点儿一点儿成长,最后完成所有的功能。
保持软件设计不退化的重点是每次需求变更的设计,只有保证每次需求变更时做出正确的设计,才可能正真的保证软件以一种良性循环的方式不断维护下去。
有没有一种方法,让我们在第十次变更、第二十次变更、第三十次变更时,依然能找到正确的设计呢?有,那就是领域驱动设计。
那么在每次需求变更时,将变更还原到真实世界中,看看真实世界是啥样子的,根据真实世界进行变更。
在一个领域/子域中,有概念上的领域边界,任何领域对象在该边界内部的有不依赖外部的确切含义。
服务、实体与值对象是领域驱动设计的领域对象,能够最终靠贫血模型和充血模型转换为程序设计
通过一个唯一标识字段来区分真实世界中的每一个个体的领域对象,称为实体。真实世界中那些一成不变的、本质性的事物的领域对象,称为值对象。可变性是实体的特点,而不变性则是值对象的本质。
POJO对象中只保存get/set方法,没有一点业务逻辑,这样的设计被称为贫血模型。
充血模型是封装和继承思想的体现,门禁设备实体中,包含特征值下发、广告下发、通行记录回调等方法,不同厂商的实体针对多态进行聚合,并通过工厂或仓库对外提供服务。在充血模型中, Service 只干一件格外的简单的事,就是直接去调用对象中的工厂方法生成不一样的产品,其他的什么都不干。
聚合体现的是一种整体与部分的关系。正是因为有这样的关系,在操作整体的时候,整体就封装了对部分的操作。如何正确理解是不是真的存在聚合的关系:就是当整体不存在时,部分就变得没有了意义。部分是整体的一个部分,与整体有相同的生命周期。
通过装配,创建领域对象,是领域对象生命周期的起点。譬如,系统要通过 ID 装载一个访客申请:
表单工厂分别调用表单信息DAO、表单明细 DAO 和用户DAO 去进行查询;
将得到的表单明细对象、用户对象进行装配,分别 set 到表单信息对象的表单明细与用户属性中;
如果服务器是一个很强大的服务器,那么我们不需要任何数据库。系统创建的所有领域对象都放在仓库中,当需要这些对象时,通过 ID 到仓库中去获取。
当客户程序通过 ID 去获取某个领域对象时,仓库会通过这一个 ID 先到缓存中进行查找:
没有找到,则通知工厂,工厂调用 DAO 去数据库中查询,然后装配成领域对象返回给仓库。
仓库在收到这样的领域对象以后,在返回给客户程序的同时,将该对象放到缓存中。
单位地址
临海市江南街道江南大道288号联系电话
400-886-7766联系邮箱
1041075843@qq.comCopyright © 2012-2018 华体会(hth)网页版 - 登录入口 版权所有 浙ICP备16019742号-4 网站地图