领域驱动设计:是一种通过将实现连接到持续进化的模型来满足复杂需求的软件开发方法(一种解决业务复杂性的设计思想,不是一种标准规则的解决方法)
领域模型是对业务模型的抽象,DDD是把业务模型翻译成系统架构设计的一种方式
模型仅仅包含对象属性的定义和操作对象的getter/setter方法
其它所有的业务逻辑完全由业务逻辑层去实现,这种类叫POJO
优点:对象结构简单
缺点:会导致业务逻辑层臃肿,难于理解和维护,无法良好的扩展复杂业务逻辑和场景
@Data
public class person {
private String name;
private String sex;
private Integer age;
}
模型包含了对象属性的定义和操作对象的getter/setter方法并且包含了对象的行为
【是完整的一个对象】
属性:姓名,性别,年龄等
行为:走路,吃饭,睡觉等
不包括依赖持久层的业务逻辑,这部分持久层的数据还是在业务逻辑层去实现,组合逻辑也是服务类负责
优点:层次结构清楚,在少量业务逻辑的服务中,容易理解,调用方无需理解内部逻辑
缺点:在复杂的逻辑和场景不太适用
@Data
public class person {
private String name;
private String sex;
private Integer age;
// 走路
public void walking(){}
// 吃东西
public void eating(){}
// 睡觉
public void sleeping(){}
}
模型包含了对象属性的定义和操作对象的getter/setter方法并且包含了对象的行为,大多数相关的业务逻辑和持久层业务逻辑
业务逻辑层(Business Logic)的业务逻辑减少,仅仅是简单封装少量业务,事务控制,权限控制等等,不和持久层打交道
充血模型是依赖持久层的
优点:符合OO(面向对象)原则,业务逻辑层很薄,符合单一职责,不像贫血模型那么业务逻辑沉重
缺点:业务逻辑不好划分,哪些业务要放在领域对象,哪些业务要放在业务逻辑层需要开发自己去判断,其次控制事务的时候要重新包装一遍,有点冗余
@Data
public class person {
private String name;
private String sex;
private Integer age;
// 走路
public void walking(String address){}
// 吃东西
public void eating(){}
// 睡觉
public void sleeping(){}
// 业务逻辑层
private PersonDao personDao;
// 查看地图再走路(问路)
public void askingTheWay(){
MapObject mapObject = personDao.getMap();
walking(mapObject.getAddress());
}
}
public class PersonDao {
private PersonMapping personMapping;
// 获取地图
public MapObject getMap(){
personMapping.getMap();
}
}
模型包含了对象属性的定义和操作对象的getter/setter方法并且包含了对象的行为,所有的业务逻辑,也包含了不相干的其它模块逻辑(如授权,事务等)
相当与直接去掉了业务逻辑层,只有领域对象和持久层,所有的逻辑在领域对象上面
优点:简化代码分层体系,符合面向对象设计
缺点:取消了业务逻辑层,会导致领域对象变得臃肿,而且容易逻辑混乱,对于代码的理解和维护性变差
@Data
public class person {
private String name;
private String sex;
private Integer age;
// 走路
public void walking(String address){}
// 吃东西
public void eating(){}
// 睡觉
public void sleeping(){}
// 业务逻辑层
private PersonMapping personMapping;
// 查看地图再走路(问路)
public void askingTheWay(){
MapObject mapObject = personMapping.getMap();
walking(mapObject.getAddress());
}
}
持久层对象它是由一组属性和属性的get和set方法组成,最简单的 PO 就是对应数据库中某个表中的一条记录(也就是说,我们可以将数据库表中的一条记录理解为一个持久层对象),多个记录可以用 PO 的集合,PO 中应该不包含任何对数据库的操作。
PO 的属性是跟数据库表的字段一一对应的,此外 PO 对象需要实现序列化接口。
ssm框架开发中一般定义为entity层
业务层对象,是简单的真实世界的软件抽象,通常位于中间层。
BO 的主要作用是把业务逻辑封装为一个对象,这个对象可以包括一个或多个其它的对象。
举一个求职简历的例子,每份简历都包括教育经历、项目经历等,我们可以让教育经历和项目经历分别对应一个 PO,这样在我们建立对应求职简历的 BO 对象处理简历的时候,让每个 BO 都包含这些 PO 即可
用于业务逻辑传输层
值对象,通常用于业务层之间的数据传递,和 PO 一样也是仅仅包含数据而已,但 VO 应该是抽象出的业务对象,可以和表对应,也可以不对应,这根据业务的需要。 如果锅碗瓢盆分别为对应的业务对象的话,那么整个碗柜就是一个值对象。
此外,VO 也可以称为页面对象,如果称为页面对象的话,那么它所代表的将是整个页面展示层的对象,也可以由需要的业务对象进行组装而来。
用于返回给前端
数据传输对象,主要用于远程调用等需要大量传输对象的地方,比如我们有一个交易订单表,含有 25 个字段,那么其对应的 PO 就有 25 个属性,但我们的页面上只需要显示 5 个字段,因此没有必要把整个 PO 对象传递给客户端,这时我们只需把仅有 5 个属性的 DTO 把结果传递给客户端即可,而且如果用这个对象来对应界面的显示对象,那此时它的身份就转为 VO。
使用 DTO 的好处有两个
一是能避免传递过多的无用数据,提高数据的传输速度;
二是能隐藏后端的表结构。
常见的用法是:将请求的数据或属性组装成一个 RequestDTO,再将响应的数据或属性组装成一个 ResponseDTO
用于接收来自客户端的参数,用于封装数据库查询的结果对象
不同的应用程序之间传输的对象
@Data
@Builder
public class Person {
private String name;
private String sex;
private Integer age;
}
@Data
@Builder
public class Teacher {
private String name;
private String sex;
private Integer ages;
private String classes;
private String course;
}
public class PersonUtils {
public static Teacher convert(Person person){
return Teacher.builder()
.name(person.getName())
.ages(person.getAge())
.sex(person.getSex())
.build();
}
}
调用
@Slf4j
public class PersonTest {
@Test
public void convert(){
Person person = Person.builder().name("张三").sex("男").age(30).build();
Teacher teacher2 = PersonUtils.convert(person);
log.info(teacher2.toString());
// 18:05:00.431 [main] INFO com.tiantai.policys.PersonTest - Teacher(name=张三, sex=男, ages=30, classes=null, course=null)
}
}
@Mapper(builder = @Builder(disableBuilder = true))
public interface PersonToTeacher {
PersonToTeacher INSTANCE = Mappers.getMapper(PersonToTeacher.class);
@Mapping(source = "age",target = "ages")
Teacher convert(Person person);
}
调用
@Slf4j
public class PersonTest {
@Test
public void convert(){
Person person = Person.builder().name("张三").sex("男").age(30).build();
Teacher teacher2 = PersonUtils.convert(person);
log.info(teacher2.toString());
// 18:05:00.431 [main] INFO com.tiantai.policys.PersonTest - Teacher(name=张三, sex=男, ages=30, classes=null, course=null)
}
}
推荐使用mapstruct,在不同的PO,BO,DTO等等之间进行转换,如果属性名称相近的话,转换速度比较快,更适合使用