领域模型(domain model)是对领域内的概念类或现实世界中对象的可视化表示。领域模型也称为概念模型、领域对象模型和分析对象模型。

——《UML和模式应用》

我们在日常开发中,经常针对一些功能点争论“这个功能不应该我改,应该是你那边改”,最终被妥协改了之后都改不明白为什么这个功能要在自己这边改。区别于传统的架构设计,领域驱动设计(DDD)也许在这个时候能帮助你做到清晰的划分。

什么是DDD

领域驱动设计最初由Eric Evans提出,但是多年以来一直停留在理念阶段,真正能实现并且落地的项目和公司少之又少,而进来阿里内部其实在大力推行DDD的理念,它主要可以帮助我们解决传统单体式集中架构难以快速响应业务需求落地的问题,并且针对中台和微服务盛行的场景做出指导。

DDD为我们提供的是架构设计的方法论,既面向技术也面向业务,从业务的角度来把握设计方案。

DDD的作用

统一思想:统一项目各方业务、产品、开发对问题的认知,而不是开发和产品统一,业务又和产品统一从而产生分歧。

明确分工:域模型需要明确定义来解决方方面面的问题,而针对这些问题则形成了团队分钟的理解。

反映变化:需求是不断变化的,因此我们的模型也是在不断的变化的。领域模型则可以真实的反映这些变化。

边界分离:领域模型与数据模型分离,用领域模型来界定哪些需求在什么地方实现,保持结构清晰。

DDD的概念

实体

有唯一标志的核心领域对象,且这个标志在整个软件生命周期中都不会发生变化。这个概念和我们平时软件模型中和数据库打交道的Model实例比较接近,唯一不同的是DDD中这些实体会包含与该实体相关的业务逻辑,它是操作行为的载体。

值对象

依附于实体存在,通过对象属性来识别的对象,它将一些相关的实体属性打包在一起处理,形成一个新的对象。

举个栗子:比如用户实体,包含用户名、密码、年龄、地址,地址又包含省市区等属性,而将省市区这些属性打包成一个属性集合就是值对象。

聚合

实体和值对象表现的是个体的能力,而我们的业务逻辑往往很复杂,依赖个体是无法完成的,这时候就需要多个实体和值对象一起协同工作,而这个协同的组织就是聚合。聚合是数据修改和持久化的基本单元,同一个聚合内要保证事务的一致性,所以在设计的时候要保证聚合的设计拆分到最小化以保证效率和性能。

聚合根

也叫做根实体,一个特殊的实体,它是聚合的管理者,代表聚合的入口,抓住聚合根可以抓住整个聚合。

领域服务

有些领域的操作是一些动词,并不能简单的把他们归类到某个实体或者值对象中。这样的行为从领域中识别出来之后应该将它声明成一个服务,它的作用仅仅是为领域提供相应的功能。

领域事件

在特定的领域由用户动作触发,表示发生在过去的事件。比如充值成功、充值失败的事件。

四种模式

失血模型

模型中只有简单的get set方法,是对一个实体最简单的封装,其他所有的业务行为由服务类来完成。

@Data
@ToString
public class User {
private Long id;
private String username;
private String password;
private Integer status;
private Date createdAt;
private Date updatedAt;
private Integer isDeleted;
}
public class UserService{
public boolean isActive(User user){
return user.getStatus().equals(StatusEnum.ACTIVE.getCode());
}
}

贫血模型

在失血模型基础之上聚合了业务领域行为,领域对象的状态变化停留在内存层面,不关心数据持久化。

@Data
@ToString
public class User {
private Long id;
private String username;
private String password;
private Integer status;
private Date createdAt;
private Date updatedAt;
private Integer isDeleted; public boolean isActive(User user){
return user.getStatus().equals(StatusEnum.ACTIVE.getCode());
} public void setUsername(String username){
return username.trim();
}
}

充血模型

在贫血模型基础上,负责数据的持久化。

@Data
@ToString
public class User {
private Long id;
private String username;
private String password;
private Integer status;
private Date createdAt;
private Date updatedAt;
private Integer isDeleted; private UserRepository userRepository; public boolean isActive(User user){
return user.getStatus().equals(StatusEnum.ACTIVE.getCode());
} public void setUsername(String username){
this.username = username.trim();
userRepository.update(user);
}
}

胀血模型

service都不需要,所有的业务逻辑、数据存储都放到一个类中。

对于DDD来说,失血和胀血都是不合适的,失血太轻量没有聚合,胀血那是初学者才这样写代码。那么充血模型和贫血模型该怎么选择?充血模型依赖repository接口,与数据存储紧密相关,有破坏程序稳定性的风险。

建模方法

用例分析法

用例分析法是领域建模最简单可行的方式。大致可以分为获取用例、收集实体、添加关联、添加属性、模型精化几个步骤。

  1. 获取用例:提取领域规则描述

  2. 收集实体:定位实体,

  3. 添加关联:两个实体间用动词关联起来

  4. 添加属性:获取实体属性

  5. 模型精化:可选的步骤,可以用UML的泛华和组合来表达模型间的关系,同时可以做子领域的划分

四色建模法

四色建模法源于《Java Modeling In Color With UML》,它是一种模型的分析和设计方法,通过把所有模型分为四种类型,帮助模型做到清晰、可追溯。

简单来说,四色关注的是某个人的角色在某个地点的角色用某个东西的角色做了某件事情。

事件风暴法

事件风暴法类似头脑风暴,简单来说就是谁在何时基于什么做了什么,产生了什么,影响了什么事情。

架构分层

区别于左图传统架构的分层,一般DDD分层会有一些变化。

Application:包含事件注册、业务逻辑等

Domain:聚合、实体、值对象

InfraStructure:基础设施封装、数据库访问等

总结

DDD是一套完善的方法论,他能帮助我们合理的对系统进行架构设计,同时,好的模板应该是在不断的适应变化,而DDD也能帮助我们更快速更方便的支撑业务的发展。

面试官:谈一下你对DDD的理解?我:马什么梅?的更多相关文章

  1. 看完这篇HTTP,跟面试官扯皮就没问题了

    我是一名程序员,我的主要编程语言是 Java,我更是一名 Web 开发人员,所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶,看完让你有一种恍然大悟.醍醐灌顶的感觉. 最初在有 ...

  2. 【MySQL】面试官:如何添加新数据库到MySQL主从复制环境?

    写在前面 今天,一名读者反馈说:自己出去面试,被面试官一顿虐啊!为什么呢?因为这名读者面试的是某大厂的研发工程师,偏技术型的.所以,在面试过程中,面试官比较偏向于问技术型的问题.不过,技术终归还是要服 ...

  3. 浅谈MySQL日志文件|手撕MySQL|对线面试官

    关注微信公众号[程序员白泽],进入白泽的知识分享星球 前言 上周五面试了字节的第三面,深感数据库知识的重要,我也意识到在平时的学习中,自己对于数据库的学习较为薄弱.甚至在有过一定实习经验之后,依旧因为 ...

  4. 面试官的七种武器:Java篇

    起源 自己经历过的面试也不少了,互联网的.外企的,都有.总结一下这些面试的经验,发现面试官问的问题其实不外乎几个大类,玩不出太多新鲜玩意的.细细想来,面试官拥有以下七种武器.恰似古龙先生笔下的武侠世界 ...

  5. 我是面试官--"自我介绍"

    工作10余年,经历过很多次面试,也面试了N多人.这些年来,已经有好些位朋友(或同事)与我聊起相关话题,涉及面试,更关乎职业生涯规划.感触颇多,就借助自媒体的浪潮,与更多的程序员一起共谈面试经历,希望可 ...

  6. 如何写出面试官欣赏的Java单例

    单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例. 今天我们不谈单例模式的用途,只说一说如果在面试的时候面试官让你敲一段代码 ...

  7. 如何解释vue的生命周期才能令面试官满意?

    当面试官问:"谈谈你对vue的生命周期的理解",听到这句话你是不是心里暗自窃喜:这也太容易了吧,不就是beforeCreate.created.beforeMount.mounte ...

  8. 金三银四,如何征服面试官,拿到Offer

    又到了茶余饭后的时间,想想写点什么,掐指一算,噢呦,快到3月份了,职场的金三银四跳槽季又来了,不同的是今年比往年「冷」一些,形式更加严峻一些,大家多多少少可能都听到或看到一些信息,就是好多公司在优化裁 ...

  9. 跟面试官聊.NET垃圾收集,直刺面试官G点

    装逼的面试官和装逼的程序员 我面试别人的时候,经常是按这种路子来面试: 看简历和面试题,从简历和面试题上找到一些技术点,然后跟应聘者聊. 聊某个技术点的时候,应聘者的回答会牵涉到其他的技术点,然后我会 ...

随机推荐

  1. Python里的目录方法

    Python里的目录_文件.目录相关的方法: mkdir(目录名): 在当前目录下创建新的目录 程序: import os # 创建新的目录-包结构 os.mkdir('新目录-test') getc ...

  2. PHP hebrevc() 函数

    实例 反向显示希伯来字符,并把新行(\n)转换为 <br>: <?php高佣联盟 www.cgewang.comecho hebrevc("á çùåï äúùñâ\ná ...

  3. 70道Spring面试题

    1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring 框架目标是简化Jav ...

  4. .Net Core 3.0下AOP试水~~

    昨天躺了一下3.0的依赖注入的雷 今天顺势把AOP做了一下调整,比如自动化的AOP注入 默认的Program里面的CreateHostBuilder方法增加一行 public static IHost ...

  5. Requests接口测试库-官网快速上手

    Requests 一个发送HTTP请求的库基于urllib3,相比自带的库,提供了更高效简洁的可用方法,测试从业者用来做接口测试的一个好工具 文章内容均来自官网:https://requests.re ...

  6. 苹果挖矿恶意程序处理(OSX/CoinMiner.X)

    背景 近期通过流量告警发现多起外连矿池的告警,均外连至43.249.204.231 威胁情报信息如下: 系统表象 1.通过ps -ef|grep osascript发现在/library/Launch ...

  7. python6.4项目:股票提醒系统

    import tushareimport timedef getdata(share): data=tushare.get_realtime_quotes(share.code) share.name ...

  8. Python-关于正则表达式的总结

    什么是正则表达式? 正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),用于字符串的 匹配 和 提取 等操作.正则表达式在所有编程语言中都是通用的. 很多人 ...

  9. JS 鼠标、键盘事件对象

    鼠标事件对象     mouseEvent鼠标事件对象     e.clientX 在可视区的x和y的坐标     e.pageX 在页面文档的X和Y的坐标 <script> docume ...

  10. CRF