DDD分层架构
DDD(Domain Driven Design,领域驱动设计)
DDD
ddd作为一种软件开方法,可以帮助我们设计高质量的软件模型,在正确实现的情况下,我们通过DDD完成的设计恰恰就是软件的工作方式
ddd是为了解决快速变化,复杂系统的设计问题的
传统的mvc模式,是面向 数据的设计
模型
贫血模型
目前几乎所有的后端系统都是基于贫血模型的.
// Controller+VO(View Object) //
public class UserController {
private UserService userService; //通过构造函数或者IOC框架注入
public UserVo getUserById(Long userId) {
UserBo userBo = userService.getUserById(userId);
UserVo userVo = [...convert userBo to userVo...];
return userVo;
}
}
public class UserVo {//省略其他属性、get/set/construct方法
private Long id;
private String name;
private String cellphone;
}
// Service+BO(Business Object) //
public class UserService {
private UserRepository userRepository; //通过构造函数或者IOC框架注入
public UserBo getUserById(Long userId) {
UserEntity userEntity = userRepository.getUserById(userId);
UserBo userBo = [...convert userEntity to userBo...];
return userBo;
}
}
public class UserBo {//省略其他属性、get/set/construct方法
private Long id;
private String name;
private String cellphone;
}
// Repository+Entity //
public class UserRepository {
public UserEntity getUserById(Long userId) { //... }
}
public class UserEntity {//省略其他属性、get/set/construct方法
private Long id;
private String name;
private String cellphone;
}
平时开发web后端项目的傻时候,基本上都是这么组织代码的,其中userEntity和USerRepository组成了数据访问层,UserBo和UserService组成了业务逻辑层,UserVo和UserController这里属于接口层
从代码中我们可以发现,UserBo是一个纯粹的数据结构,只包含数据,不包含任何的业务逻辑,业务逻辑集中在UserSErvice中,我们通过UserSErvice来操作UserBo.换句话说,Service层的数据业务逻辑,被分割为Bo和Service俩个类中,像UserBo这样,只包含数据,不包含逻辑的类,就叫做贫血模型,同理UserEntity,UserVo都是基于贫血模型设计的.这种贫血模型讲数据与操作分离,这种分离直观上就不是在同一个类里,就和一个车只有车的特点,破坏了面向对象封装的的特效,是一种典型的面向过程的编程风格.
充血模型
什么是基于充血模型的DDD开发模式
在贫血模型中,数据和业务逻辑被风格到不同的类中,充血模型正好相反,数据和对应的业务逻辑被封装到同一个类中.因此这种充血模型满足面向对象的封装性,是典型的面向对象风格编程.
什么是驱动领设计
驱动领域设计即DDD,主要是用来知道如何解耦业务逻辑,划分业务模块,定义业务领域模型及其交互.领域驱动设计这个概念在04年被提出,到现在已经有十几年的历史了.不过它被大众熟知,是因为另一个概念的兴起,那就是微服务
我们知道,除了监控、调用链追踪、API 网关等服务治理系统的开发之外,微服务还有另外一个更加重要的工作,那就是针对公司的业务,合理地做微服务拆分。而领域驱动设计恰好就是用来指导划分服务的。所以,微服务加速了领域驱动设计的盛行。
实际上基于充血模型的DDD开发模式实现的代码,也是按照mvc三层架构分层的.Controller层还是负责暴露接口,Repository还是负责数据存取,Service层负责核心业务逻辑.它跟基于贫血模型的传统开发模式的区别主要在Service层.
在贫血模型的传统开发模式中,Service层包含Service类和Bo类俩部分,Bo是贫血模型,只包含数据,不包含具体的业务逻辑.业务逻辑在Serivce类中.在基于充血模型的DDD开发模式中,Service层包含Service类和Domain类俩部分.Domain就相当于贫血模型中的BO,区别是基于充血模型开发的,既包含数据,也包含业务逻辑.总结一下的话就是,基于贫血模型的传统的开发模式,重 Service 轻 BO;基于充血模型的 DDD 开发模式,轻 Service 重 Domain。
为什么传统模式如此受欢迎
- 大部分情况下,开发系统业务都比较简单,不需要精心设计充血模型,
- 充血模型的设计比贫血模型更有难度
- 传统开发模式转型有成本,没有遇到开发痛点情况下大多不愿意转型
转载自(32条消息) 什么是贫血模型?Limonare的博客-CSDN博客贫血模型
mvc保证了最差也差不到哪去(一般都是最差),DDD如果做得差,会做的比MVC还要差,如果做的好,的确可以应对业务的变化
归约
什么是归约模式,用来将业务规则(通常是隐式业务关于则)封装成独立的逻辑单元,从而将隐式业务规则提炼为显示概念,并达到代码复用的目的
什么是隐式业务规则,假如开发了一个网站,目标用户是18岁以上人群,当地政策不允许18岁以下浏览,如何验证用户符合需求呢
public ActionResult Register(UserRegisterInfo user){
if(user.Age < 18){
throw new Exception("Too young too simple...");
}
}
在Register方法中if语句就是一条隐式业务规则
当然这样写也能满足业务规则,但是改天新来一个程序员,没闹明白为啥要加if判断、或者没闹明白为啥是18,,修改了代码,业务完整性就被破坏了。
public ActionResult Register(UserRegisterInfo user){
var specification = new UserMustBeAdultSpecification();
if(!specification.IsSatisfiedBy(user)){
throw new Exception("Too young too simple...");
}
//todo:注册逻辑
}
class UserMustBeAdultSpecification {
private int adultAge;
public UserMustBeAdultSpecification(int adultAge = 18){
this.adultAge = adultAge;
}
public IsSatisfiedBy(UserRegisterInfo user){
return user.Age > this.adultAge;
}
}
我们把if判断提炼成一个显示概念,用来确认用户必须是成人。这样新人来了以后,也不至于揣着明白装糊涂。
为什么要归约
通常业务不会仅仅验证一下年龄那么简单,比如订单提交,需要验证用户账号是否可用,订单的库存是否满足预定量,配送地址是否完整...如果仅仅是通过一连串的if判断,那就真的太不利于维护了,并且if嵌套了多的代码难于理解,不好说明白意图.一次需要隐式转换成显式概念,这也是DDD的要求
比如网站不仅需要注册,还可能有更新用户信息的功能,更新的时候我们任然需要确认用户必须是成人,