欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习
1 文章概述
1.1 前文回顾
本文我们继续讨论《五个分层维度:SpringBoot工程分层实战》,在这篇文章我们将一个工程分为九层:
- 工具层:util
- 整合层:integration
- 基础层:infrastructure
- 服务层:service
- 领域层:domain
- 门面层:facade
- 控制层:controller
- 客户端:client
- 启动层:boot
本文重点讨论以下层次:
- 基础层:infrastructure
- 服务层:service
- 门面层:facade
- 客户端:client
1.2 需求讨论
现在有一个需求:根据ID查询球员基本信息
第一步定义数据对象,infrastructure层使用
public class PlayerEntity {
private Long id;
private String playerId;
private String playerName;
private Integer height;
private Integer weight;
private String creator;
private String updator;
private Date createTime;
private Date updateTime;
private String gamePerformance; // 比赛表现
}
第二步定义领域对象,service层使用
public class PlayerQueryResultDomain {
private String playerId;
private String playerName;
private Integer height;
private Integer weight;
private GamePerformanceVO gamePerformance;
private MaintainCreateVO creatorInfo;
private MaintainCreateVO updatorInfo;
}
public class GamePerformanceVO {
// 跑动距离
private Double runDistance;
// 传球成功率
private Double passSuccess;
// 进球数
private Integer scoreNum;
}
public class MaintainCreateVO {
// 创建人
private String creator;
// 创建时间
private Date createTime;
}
public class MaintainUpdateVO {
// 修改人
private String updator;
// 修改时间
private Date updateTime;
}
第三步数据传输对象,facade和client层使用
public class PlayerQueryResultDTO implements Serializable {
private String playerName;
private Integer height;
private Integer weight;
private GamePerformanceDTO gamePerformanceDTO;
}
public interface PlayerClientService {
public ResultDTO<PlayerQueryResultDTO> queryById(String playerId);
}
public class PlayerClientServiceImpl implements PlayerClientService {
@Resource
private PlayerService playerService;
@Resource
private PlayerFacadeAdapter playerFacadeAdapter;
@Override
public ResultDTO<PlayerQueryResultDTO> queryById(String playerId) {
PlayerQueryResultDomain resultDomain = playerService.queryPlayerById(playerId);
if (null == resultDomain) {
return ResultCommonDTO.success();
}
PlayerQueryResultDTO result = playerFacadeAdapter.convertQuery(resultDomain);
return ResultCommonDTO.success(result);
}
}
1.3 三者比较
- 数据对象关注数据持久化,字段可以使用松散结构存储
- 领域对象关注强业务性,字段必须明确表达业务含义
- 传输对象关注对外传输,必须保证简洁性和安全性
2 变化多端
2.1 业务三端
一个系统在业务上通常分为三个端:
- 面向B端用户
- 面向C端用户
- 面向运营用户
在领域对象和数据对象转换时,因为每个端所需字段不同,所以需要三类转换:
- domain <-> 面向B端DTO
- domain <-> 面向C端DTO
- domain <-> 面向运营DTO
2.2 在同一个工程处理
2.2.1 传输对象
// 面向B端用户
public class PlayerQueryBusinessResultDTO implements Serializable {
}
// 面向C端用户
public class PlayerQueryCustomerResultDTO implements Serializable {
}
// 面向运营用户
public class PlayerQueryManagementResultDTO implements Serializable {
}
2.2.2 对外服务
// 面向B端服务
public interface PlayerBusinessClientService {
public ResultDTO<PlayerQueryBusinessResultDTO> queryById(String playerId);
}
// 面向C端服务
public interface PlayerCustomerClientService {
public ResultDTO<PlayerQueryCustomerResultDTO> queryById(String playerId);
}
// 面向运营服务
public interface PlayerManagementClientService {
public ResultDTO<PlayerQueryManagementResultDTO> queryById(String playerId);
}
2.3 应用拆分
在同一个应用中处理不同端对象转换会有两个问题:
第一应用过大,第二违背前后端分离原则,因为后端要理解前端数据
面对这种情况可以划分前台、中台、后台三类应用:
第一点上图所有应用都可以使用九层结构。
第二点中台应用承载核心逻辑,暴露核心接口,中台并不要理解所有端数据结构,而是通过client接口暴露相对稳定的数据。
第三点针对面向B端、面向C端、面向运营三种端,各自拆分出一个应用,在此应用中进行转换、适配和裁剪,并且处理各自业务。
第四点什么是大中台、小前台思想?中台提供稳定服务,前台提供灵活入口。
第五点如果后续要做秒杀系统,那么也可以理解其为一个前台应用(seckill-front)聚合各种中台接口。
3 文章总结
第一本文回顾了《五个分层维度:SpringBoot工程分层实战》文章,第二本文介绍了业务通用三端:面向B端、面向C端、面向运营,解决多端问题有两种方案:方案一是在同一个应用处理,方案二是拆分为多个应用。第三本文通过五点分析了为什么选择方案二,最终得出入口要灵活、服务要稳定。
欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习