领域驱动设计DDD简介
软件负责性与开发周期关系
DDD经典分层
- 用户界面/展示层:负责向用户展现信息,并且会解析用户行为,也就是说常说的展现层
- 应用层:应用层没有任何业务逻辑代码,它很简单,它主要为程序提供任务处理。应用层不包括业务逻辑
- 领域层:表达业务概念、业务状态信息及业务规则,是业务软件的核心
- 基础设施层:为其他层提供通用的技术能力,提供了层间通信;为领域层提供持久化机制。
DDD领域模型
-紧密联系在一起的业务称作一个领域模型
- 以一种领域专家、设计人员、开发人员都能理解的通用语言作为互相交流的工具,在交流过程中发现领域概念,然后将这些概念设计成一个领域模型
DDD的一些概念
实体(Entity)
值对象(ValueObject)
服务(Service)
- 服务中体现的行为一定是不属于任何实体和值对象的,但它属于领域模型的范围内
- 服务的行为一定涉及其他多个对象
- 服务的操作是无状态的
仓库(Repository)
获取对象的逻辑,是对数据增删查改的操作
DDD步骤
- 根据需求建立初步的领域模型,识别出一些明显的领域概念以及他们的关联
- 分析程序功能,识别出应用层和领域层的职责
- 识别Entity,Value Object,Service等
- 找出Aggregate Root
- 为Aggregate写Repository
- 走查场景,分析领域模型能否解决业务需求
- 创建考虑Entity,Value Object,Aggregate
- 重构模型
DDD精髓
设计时首先考虑Domain层
设计领域模型
ABP简介
ABP总体介绍
ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称,ABP基于DDD的经典分层架构思想,实现了众多DDD的概念(但没有实现所有DDD的概念)。
- 多语言/本地化支持
- 多租户支持(每个租户的数据自动隔离,业务模块开发者不需要在保存和查询数时写相应代码)
- 软删除支持(继承相应的基类或实现相应接口,会自动实现软删除)
- 统一的异常处理(应用层几乎不需要自己写异常处理代码)
- 数据有效性验证(Asp.NET MVC只能做到Action方法的参数验证,ABP实现了Application层方法的参数有效性验证)
- 日志记录(自动记录程序异常)
- 模块化开发(每个模块有独立的EF DbContext,可单独指定数据库)
- Repository仓储模式(已实现了Entity Framework、NHibernate、MangoDB、内存数据库)
- Unit Of Work工作单元模式(为应用层和仓储层的方法自动实现数据库事务)
- EventBus实现领域事件(Domain Events)
- DLL嵌入资源管理
- 通过Application Services自动创建Web Api层(不需要写ApiController层了)
- 自动创建Javascript 的代理层来更方便使用Web Api
- 封装一些Javascript 函数,更方便地使用ajax、消息框、通知组件、忙状态的遮罩层
ABP体系结构
ABP工程实践
生成数据库命令
- 把Web.Host设置成启动工程
- 修改Web.Host中appsettings.json的连接字符串
- 打开 PackageManager Console
- Default Project选择 EntityFrameworkCore
- Add-Migration “[migrationName]”
- Update-Database
Entity,Repository,Dto
- Entity,实体
- Value Object值对象
- Repository,仓储
- Dto,数据传输对象
AutoMapper
- 选择使用IDtoMapping接口方式
internal interface IDtoMapping
{
void CreateMapping(IMapperConfigurationExpression mapperConfig);
}
- 在ApplicationModule.cs配置AutoMapping
//注册IDtoMapping
IocManager.IocContainer.Register(
Classes.FromAssembly(System.Reflection.Assembly.GetExecutingAssembly())
.IncludeNonPublicTypes()
.BasedOn<IDtoMapping>()
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleTransient());
Configuration.Modules.AbpAutoMapper().Configurators.Add(mapper =>
{
var mappers = IocManager.IocContainer.ResolveAll<IDtoMapping>();
foreach (var dtomap in mappers)
dtomap.CreateMapping(mapper);
});
- Application工程中继承IDtoMapping,创建Map规则
public class StudentDtoMapping : IDtoMapping
{
public void CreateMapping(IMapperConfigurationExpression mapperConfig)
{
mapperConfig.CreateMap<Student,StudentOutput>();
}
}
Session
ABP在 ApplicationService中注入了IAbpSession,可以在继承ApplicationService中直接使用,包含如下属性:
UserId: 当前用户的标识ID,如果没有当前用户则为null。如果调用的代码是已授权,那么它不可能为空。
TenantId: 当前租户的标识ID,如果没有当前租户则为null(如果用户没有登录或者他是一个Host用户)。
ImpersonatorUserId: 模拟用户的标识ID,如果当前会话被其他用户模拟登录。如果不是一个模拟登录,那么该值为空。
ImpersonatorTenantId: 模拟用户租户的标识ID,如果当前会话被其他用户模拟登录。如果不是一个模拟登录,那么该值为空。
MultiTenancySide: 可能是Host或Tenant。
工作单元
当进入某个事务单元 的时候,ABP 会 打开 数据库的连接,并开始 事务 操作(它可能不会立即打开,但是会在首次使用数据库的时候打开)。所以你可以安全在这个方法中使用连接。在该方法的最后,该事务会被提交,且该连接会被 释放。如果该方法抛出任何异常,事务会回滚且连接会被释放。通过这种方式,工作单元方法是原子性的。ABP会自动的执行这些操作。
如果工作单元方法调用其它工作单元的方法,它们使用相同的连接和事务。第一个进入的方法管理连接和事务,其它只是使用它。
网友评论