Apworks框架实战(五):EasyMemo的领域模型设计
在上一讲中,我们已经新建了一个聚合根对象Account,并已经可以开始设计领域模型了。在这一讲中,我们会着重介绍EasyMemo领域模型的分析和设计,并引入Visual Studio Ultimate(旗舰版)版本的特性,介绍在Visual Studio 2013 Ultimate中如何使用体系结构建模工具进行领域模型设计,并自动化产生支持Apworks框架的代码。
界定上下文
由于EasyMemo所需实现的功能非常简单,因此,我们很容易从领域概念中剥离出两个界定上下文:用户账户上下文和用户便签上下文。前者主要描述与用户账户相关的领域模型,比如账户、角色、权限、授权等;而后者则更侧重于与便签相关的部分。在实践中,由于EasyMemo的业务非常简单,我们并没有必要对它进行严格的上下文区分,在此引入界定上下文区分,主要是为了之后对Visual Studio 2013 Ultimate体系结构工具的介绍进行铺垫。
用户账户领域模型
用户账户领域模型包含了与账户及其权限相关的概念和对象,以及它们之间的关系和行为。在EasyMemo中,我们会采用基于角色的访问控制(Role Based Access Control,RBAC),相信这也是比较主流的一种权限认证和授权方式。当然,它有一些弊端,比如对于资源的访问授权(Privilege)类型不容易扩展,在一般的应用系统中,更偏向于将访问授权类型固定下来。比如:某个应用仅提供“系统管理”、“账户添加”、“账户管理”等有限个授权类型,而且在整个程序运行过程中,这些授权类型是不能动态改变的。需要增加新的授权类型,则需要改变源代码并重新生成,或者稍微好一点,修改数据库中的固定值。不管怎样,RBAC是好是不好,这里就不多纠结了,在本文案例中,我们还是尝试着实现一个简单的RBAC模型吧。
用户账户领域模型中最显著的一个领域对象就是【账户(Account)】,在上文中,我们已经向EasyMemo.Domain类库中添加了这个对象。既然是基于角色的访问控制,那么【角色(Role)】也是一个领域对象,或者更确切地说,是一个聚合根。现在的问题是,【账户】聚合与【角色】聚合的关系是什么?
这就要看我们是如何理解这个问题的,如果【账户】的存在必须依赖于【角色】(也就是不存在一个不属于任何角色的账户),那么【角色】聚合就可以引用【账户】聚合,因为后者的生命周期比前者短(如果角色聚合生命周期结束,那么账户也就没有存在的意义);反之,【角色】的存在需要依赖【账户】吗?显然多数情形下不是。或许,两者互不依赖的关系更为合理,不过此时需要引入另一个领域概念,表述【账户】与【角色】之间的“从属”关联。这种关联可以是实体,也可以是值对象,它的生命周期依赖于其所在的聚合。本文所设计的用户账户领域模型暂不会引入这样的关联实体,这也是为了让事情变得更为简单。不管如何,【账户】与【角色】之间的这种逻辑从属关系,应该是容易被人理解的。
接下来的问题就是如何针对【角色】设定权限。基本上这类需求可以通过“某种角色针对某种授权类型具有某种控制能力”一句话概括。那么如何理解这句话?
- 某种角色:也就是在领域模型中【角色】的概念
- 某种授权类型:表示在领域模型中针对资源操作的一种分类。比如,“系统管理”、“账户添加”、“发布文章”等,都属于授权类型的一种。原则上,授权类型是可以组合的,比如具有“系统管理”授权的访问者,当然可以访问由“账户添加”授权标记的资源
- 某种控制能力:也就是角色对授权类型的权限,最简单的就是“允许”和“拒绝”两种
把上面的理解串联起来,我们就可以得到类似“(系统管理员)针对被(发布文章)标记的资源,具有(允许)的访问权限”这样的描述。于是,如果某个账户具有系统管理员身份,那么它就可以发布文章。这部分概念可以简单地使用以下模型进行表述:
在下面的章节中,我们会使用Visual Studio 2013 Ultimate(旗舰版)的建模功能来完善这个模型。
用户便签领域模型
用户便签领域模型就非常简单了,我们打算只包含一个【便签】的对象,它定义了便签的基本属性和一些简单的业务逻辑,在此就不多作说明了,在后续的实践中再慢慢引入吧。
使用Visual Studio 2013 Ultimate(旗舰版)进行领域模型设计与自动化代码生成
首先声明一点,本节内容需要依赖于Visual Studio 2013 Ultimate(旗舰版),其它版本的Visual Studio 2013将无法完成本节所演示的内容。如果您所使用的VS2013不是旗舰版,您可以跳过本节内容的阅读,当然,也可以继续阅读,以了解旗舰版所提供的体系结构工具的使用方法。
现在,领域特定语言是一种潮流,它也是领域驱动设计所支持的一种用于交流的通用语言。通过工具进行模型设计并自动化产生代码,不仅可以更方便地以图形化的方式与团队进行架构设计讨论,而且还可以加快开发速度,大大降低出错几率。接下来,就让我们一起学习,看看如何在Visual Studio 2013 Ultimate(旗舰版)中,结合Apworks的建模插件,实现领域模型的设计与自动化代码生成。
先决条件
要对本节所讨论的内容进行演练,在开始前,您需要确认您的系统是否满足以下先决条件:
- 安装Visual Studio 2013 Ultimate(旗舰版)
- 安装Apworks建模插件:请【单击此处】下载Apworks建模插件。在解开的压缩包中,有VS2013和VS2015两个版本,强烈建议使用VS2013,因为在VS2015的自动化代码产生中,存在一些缺陷,目前无法正常生成代码。这是Visual Studio 2015的问题,目前未决
- 下载Apworks定制的类型生成模板T4文件,并保存在本地备用:请【单击此处】下载
Apworks建模插件包含了对Visual Studio体系结构工具UML语言的扩展,增加了两个Stereotype,分别是aggregate root和entity。在自动化代码生成时,T4引擎会根据不同的stereotype标注来决定产生不同的代码结构。
新建建模项目
在EasyMemo解决方案上单击鼠标右键,选择【添加】->【新建项目】菜单。在弹出的【添加新项目】对话框中,选择【建模项目】,取名为EasyMemo.Design,然后单击【确定】按钮:
环境设定与配置
打开【UML模型资源管理器】,在EasyMemo.Design模型上单击鼠标右键,选择【属性】:
在【属性】工具窗中,展开【通用】节点,在【Profiles】项目上打开下拉列表,然后勾选【C# Profile】和【Apworks Entity Profile】两项:
在Visual Studio IDE的主菜单上,点击【体系结构】-> 【新建关系图】菜单,此时会打开【添加新关系图】对话框。
在【添加新关系图】对话框中,选择【UML类图】,在【名称】一栏输入Model.classdiagram,【添加到建模项目】一栏选择EasyMemo.Design,然后点击【确定】按钮:
此时,Visual Studio会自动打开Model类图的设计界面,供用户对类图进行设计。在此之前,我们仍然需要对环境进行配置,以便能够在接下来的步骤中正确地产生代码。首先,在文件系统中打开EasyMemo.Design项目所在的目录,然后将已经下载好的Apworks定制的类型生成T4模板解压到Templates子目录下:
为了今后的操作方便,强烈建议在【解决方案资源管理器】中,在EasyMemo.Design项目上显示所有文件,并把这个Templates文件夹【包括在项目中】:
在Visual Studio IDE的主菜单上,点击【体系结构】 –> 【配置默认代码生成设置】菜单,打开【文本模板绑定】对话框:
在【文本模板绑定】对话框中,依次针对ClassTemplate、EnumTemplate、InterfaceTemplate以及StructTemplate进行设置:
- 【模板文件路径(*.t4)】选择EasyMemo.Design文件系统目录下Templates文件夹中的相应文件,例如ClassTemplate.t4、EnumTemplate.t4、InterfaceTemplate.t4以及StructTemplate.t4
- 我们打算将C#代码生成到EasyMemo.Domain项目的Model文件夹下,因此,在【目标文件目录】中直接输入【Model】,在【项目路径】中设置EasyMemo.Domain.csproj项目
单击【确定】按钮关闭对话框。
开始使用
OK,现在我们就可以开始使用类图设计器设计我们的领域模型了。打开【工具箱】,选择【类】工具,在类图设计器上添加一个类,并改名为AggregateRoot:
点击该类,在【属性】页中,在【Stereotypes】下拉列表中,勾选【C# class】和【aggregate root】两个stereotypes:
继续展开【Stereotypes】节点下的【C# class】节点,设置【Is Partial】属性为True,并在【继承】分组中,设置【Is Abstract】属性为True:
在AggregateRoot类上单击鼠标右键,选择【添加】->【特性】菜单项,添加一个名称为ID、类型为Guid的特性,并以同样的方式添加一个名称为IsDeleted,类型为Nullable<bool>的特性。在添加完这两个特性后,AggregateRoot类如下:
现在,让我们尝试代码生成。在类图设计器的空白区域单击鼠标右键,选择【生成代码】:
在【代码生成】进度窗口完成操作后,你会发现,在我们的EasyMemo.Domain项目下,多了一个Model的目录,在这个目录下,生成了AggregateRoot.cs文件:
双击打开这个文件,可以看到生成的源代码如下:
可以关注以下几点:
- AggregateRoot类是抽象类,因为之前我们设置了【Is Abstract】属性为True
- AggregateRoot类是部分类,因为之前我们在【C# class】stereotype中设置了【Is Partial】属性为True
- AggregateRoot类实现了Apworks.IAggregateRoot接口,因为我们对其应用了【aggregate root】stereotype
- 所有的特性(属性)都是虚实现(virtual),因为每个特性的【Is Leaf】属性值默认都是False:这在接下来使用Entity Framework的延迟加载特性会很有帮助。当然,据说Entity Framework 7已经取消了延迟加载功能
您或许会发现,这个类怎么没有包含的命名空间?不错,要设定生成代码的命名空间,您还需要对类图做一些改动:
- 打开类图设计器,在【工具箱】中,找到【包】工具,往类图设计器中添加一个【包】
- 选中Package 1包,在【属性】的【Stereotypes】下拉列表中,勾选【C# namespace】
- 将Package 1包的【Name】属性设置为EasyMemo.Domain.Model
- 将AggregateRoot类拖入EasyMemo.Domain.Model包,此时我们的类图如下:
OK,再次生成代码,可以看到,生成的代码中已经包含了命名空间定义了:
对界定上下文的支持
Visual Studio 2013 Ultimate的体系结构建模系统是以模型为单位的,也就是说,即使你向你的建模项目中添加了多个类图,这些类图也都是公用一个模型。例如,我们可以在EasyMemo.Design项目中再新建一个名称为Accounts的类图,表示用户账户领域模型,然后在这个类图中以上述类似的方式将Account类设计出来:
由于Account类本身应该继承于AggregateRoot类,因此,我们可以直接从【UML模型资源管理器】中,找到AggregateRoot类的定义,然后用拖拽的方式添加到Accounts类设计器中
从【UML工具箱】中选中【继承】工具,然后用鼠标从Account类拖到AggregateRoot类,表示前者从后者继承。在设定了这一类关系后,我们的类图如下:
OK,再次生成代码,可以看到,新出现的Account.cs文件内容如下:
完成我们的领域模型
至此,我们已经能够在Visual Studio 2013 Ultimate中使用体系结构和建模工具来图形化设计领域模型,以及自动化代码的生成了。现在,就让我们一起完成EasyMemo的领域模型吧。
贫血模型???
是的,通过类图设计器设计的领域模型不包含任何方法定义。事实上也没办法在类图上编写类中各方法的源代码。还记得之前我们在【C# class】这一stereotype上设置【Is Partial】为True吗?这就使得我们有办法在已有的类型上在不改变自动生成的代码的基础上,加入我们自己的业务逻辑:只需使用C#中部分类的特性即可!
总结
本文首先简单介绍了EasyMemo的界定上下文以及领域模型,并详细介绍了在Visual Studio 2013 Ultimate(旗舰版)中使用体系结构建模工具和Apworks的建模扩展进行领域模型的设计,并实现代码自动化生成。下一讲我将重点介绍基于Entity Framework的仓储实现。
源代码下载
请【单击此处】下载截止到本文时EasyMemo的源代码。如果您的Visual Studio 2013不是旗舰版,您也可以正常打开EasyMemo.sln解决方案,但无法打开EasyMemo.Design项目。但这并不会对你使用整个解决方案带来不便,您只需将EasyMemo.Design项目从解决方案中移除出去就可以了。
Apworks框架实战(五):EasyMemo的领域模型设计的更多相关文章
- Apworks框架实战
Apworks框架实战(一):Apworks到底是什么? Apworks框架实战(二):开始使用 Apworks框架实战(三):单元测试与持续集成 Apworks框架实战(四):使用Visual St ...
- Apworks框架实战(四):使用Visual Studio开发面向经典分层架构的应用程序:从EasyMemo案例开始
时隔一年,继续我们的Apworks框架之旅.在接下来的文章中,我将逐渐向大家介绍如何在Visual Studio中结合Apworks框架,使用ASP.NET Web API和MVC来开发面向经典分层架 ...
- Apworks框架实战(一):Apworks到底是什么?
简介 Apworks是一款基于Microsoft .NET的面向领域驱动的企业级应用程序开发框架,它适用于以领域模型为核心的企业级系统的开发和集成.Apworks不仅能够很好地支持经典的分层架构,而且 ...
- Apworks框架实战(六):使用基于Entity Framework的仓储基础结构
在前面的章节中,我们已经设计了一个简单的领域模型,接下来我们希望能够实现领域模型的持久化及查询.在Apworks中,实现了面向Entity Framework.NHibernate以及MongoDB的 ...
- Apworks框架实战(三):单元测试与持续集成
虽然这部分内容并没有过多地讨论Apworks框架的使用,但这部分内容非常重要,它与Apworks框架本身的设计紧密相关,也是进一步了解Apworks框架设计的必修课. 单元测试与持续集成概述 在敏捷开 ...
- Apworks框架实战(二):开始使用
要使用Apworks进行应用程序开发,您需要安装Visual Studio 2012以上的版本(以下简称Visual Studio 2012+),从Apworks 2.5开始,需要Micrsoft.N ...
- 应用程序框架实战十五:DDD分层架构之领域实体(验证篇)
在应用程序框架实战十四:DDD分层架构之领域实体(基础篇)一文中,我介绍了领域实体的基础,包括标识.相等性比较.输出实体状态等.本文将介绍领域实体的一个核心内容——验证,它是应用程序健壮性的基石.为了 ...
- 手把手和你一起实现一个Web框架实战——EzWeb框架(五)[Go语言笔记]Go项目实战
手把手和你一起实现一个Web框架实战--EzWeb框架(五)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 本篇代码,请选择demo5 中间件实现 ...
- 应用程序框架实战二十二 : DDD分层架构之仓储(层超类型基础篇)
前一篇介绍了仓储的基本概念,并谈了我对仓储的一些认识,本文将实现仓储的基本功能. 仓储代表聚合在内存中的集合,所以仓储的接口需要模拟得像一个集合.仓储中有很多操作都是可以通用的,可以把这部分操作抽取到 ...
随机推荐
- Gradle配置APK自动签名完整流程
转载请注明出处:http://www.cnblogs.com/LT5505/p/6256683.html 一.生成签名 1.命令行生成签名,输入命令keytool -genkey -v -keysto ...
- 关于微软HttpClient使用,避免踩坑
最近公司对于WebApi的场景使用也越来越加大了,随之而来就是Api的客户端工具我们使用哪个?我们最常用的估计就是HttpClient,在微软类库中命名空间地址:System.Net.Http,是一个 ...
- 利用Node.js的Net模块实现一个命令行多人聊天室
1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...
- 通过VMware的PowerCLI配置集群内指定主机的vMotion功能
PowerCLI是VMware开发的基于微软(MSFT)的PowerShell的命令行管理vSphere的实现,因此在批量化操作方面CLI会减轻很多GUI环境下的繁琐重复劳作. 现有场景中有大量的物理 ...
- 基于fis3的组件可视化道路
首先说明一下,即使不熟悉fis3,阅读文本应该也会有所收获. 本文以fis-parser-imweb-tplv2插件为模板插件,目的不在于使用哪个模板,而是组件可视化的实现思路,不必担心. 先说说模板 ...
- Node.js学习笔记——Node.js开发Web后台服务
一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...
- Android之网络数据存储
一.网络保存数据介绍 可以使用网络来保存数据,在需要的时候从网络上获取数据,进而显示在App中. 用网络保存数据的方法有很多种,对于不同的网络数据采用不同的上传与获取方法. 本文利用LeanCloud ...
- HTML5 标签 details 展开 搜索
details有一个新增加的子标签--summary,当鼠标点击summary标签中的内容文字时,details标签中的其他所有元素将会展开或收缩. 默认状态为 收缩状态 设置为展开状态为 <d ...
- 项目自动化建构工具gradle 入门1——输出helloWorld
先来一个简单的例子,4个步骤: 1.进入D:\work\gradle\java 目录 ,您电脑没这目录? 那辛苦自己一级一级建立起来吧 新建文件build.gradle,文件内容是: apply p ...
- EMD分析 Matlab 精华总结 附开源工具箱(全)
前言: 本贴写于2016年12与15日,UK.最近在学习EMD(Empirical Mode Decomposition)和HHT(Hilbert-Huang Transform)多分辨信号处理,FQ ...