领域驱动设计

1.基本概念

VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。简称为页面对象。

DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。

DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。

PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性。

模型:

用户发出请求(可能是填写表单),表单的数据在展示层被匹配为VO。

展示层把VO转换为服务层对应方法所要求的DTO,传送给服务层。

服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。

服务层把DO转换为持久层对应的PO(可以使用ORM工具,也可以不用),调用持久层的持久化方法,把PO传递给它,完成持久化操作。

对于一个逆向操作,如读取数据,也是用类似的方式转换和传递,略。

2.基于DDD模型的微服务分层架构图

 

3.dto的应用实例

3.1 需求分析

现有学生表,课程表,分数表,这三张表,要求通过学号查询出学生信息,包含课程和分数,这里我们采用dto思想进行操作。

3.2 代码实现

编写转换器,将实体类换成dto对象

package com.gh.blog.dto;

import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;

public interface Convert<DTO, ENTITY> {

    /**
     * 把ENTITY转换为DTO
     * @param entity
     * @return
     */
    default DTO convertFrom(ENTITY entity) {
        try {
            BeanUtils.copyProperties(entity, this);
            return (DTO)this;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("系统异常");
        }

    }

    /**
     * 把List<ENTITY>转换为List<DTO>
     * @param entities
     * @return
     */
    default List<DTO> convertFrom(List<ENTITY> entities) {
        List dtoList = new ArrayList();
        for (ENTITY entity : entities) {
            try {
                // 反射当前对象,Obj就是指的当前对象,也就是ArticleDTO
                Object dto = this.getClass().newInstance();

                // 拷贝参数,把entity中的参数数据,拷贝到obj
                BeanUtils.copyProperties(entity, dto);
                dtoList.add(dto);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("系统异常");
            }

        }
        return dtoList;
    }

    /**
     * 把page<ENTITY>转换为page<DTO>
     * @param page
     * @return
     */
    default PageInfo<DTO> convertFrom(PageInfo page) {
        // 把page<Article>的list取出,进行转换
        List<ENTITY> entities = page.getList();

        // 把Article的list转换为ArticleDTO的list
        List<DTO> dtos = convertFrom(entities);

        // 更换page的内容
        page.setList(dtos);
        return page;
    }
}

我们这里返回给页面的一个dto对象

@Getter
@Setter
public class StudentDetailDTO implements Convert<StudentDetailDTO, Student> {

    private String no;
    private String name;
    private Boolean sex;
    private Date birthday;
    private Date inSchoolDay;
    private String classCode;
    private String phone;
    private String homeAddress;

    private List<ScoreDTO> scores;
    
}

这里的dto包含了ScoreDTO进一步进行封装

@Getter
@Setter
public class ScoreDTO implements Convert<ScoreDTO, Score> {

    private Double score;

    private Course course;
    
}

controller的实现

    @GetMapping("detail")
    public StudentDetailDTO studentDetail(String no) {
        StudentDetailDTO studentDetail = stuService.findDetail(no);

        return studentDetail;
    }

service实现类

    @Override
    public StudentDetailDTO findDetail(String no) {
        // 查询学生信息并转换为dto
        StudentDetailDTO studentDetail = new StudentDetailDTO().convertFrom(stuMapper.findByNo(no));
        // 查询学生全部成绩
        List<ScoreDTO> scores = new ArrayList<>();
        //根据学号查成绩,然后拿到该学生的所有成绩,进行遍历
        for (Score item : scoreMapper.listByStudentNo(no)) {
            //把学生成绩用dto封装
            ScoreDTO score = new ScoreDTO().convertFrom(item);
            // 查询成绩对应课程
            Course course = courseMapper.getByCode(item.getCourseNo());
            score.setCourse(course);
            scores.add(score);
        }
        studentDetail.setScores(scores);
        return studentDetail;
    }

dao是简单的单表查询操作,省略不写

一点点学习,一丝丝进步。不懈怠,才不会被时代所淘汰!

原文地址:https://www.cnblogs.com/fqh2020/p/14844383.html