《Pro ASP.NET MVC 3 Framework》学习笔记之四【领域模型介绍】

主题:应用领域驱动开发(Applying Domain-Driven Development)

Domain Model是MVC程序的"心脏",其他的一切,包括Controllers和Views仅仅是用来跟Domain Model交互的一种方式,ASP.NET MVC并没有限制使用在Domain Model上面的技术,我们可以自由的选择跟.net framework交互的技术,并且这样的选择是非常多的。不仅如此,ASP.NET MVC为我们提供了基础的架构和约定来帮助Domain Model里面的Classes跟Controllers和Views的联系,也包括跟MVC自己的联系。

它们有三个关键的功能,如下所示:

a.模型绑定(Model Binding):是自动使用HTML表单提交的数据来组织领域对象(Domain Objects)基础的约定。

b.模型元数据(Model metadata):描述了Model Classes对.net的所要表达的意思。举例而言,就是给属性赋予一个人容易理解的表述或者是对属性呈现时的一些提示。asp.net mvc能够自动的识别并对Model Classes合理的呈现到Views里面。

c.验证(Validation):能够在模型绑定时被执行,并且能够应用被定义为元素据的那些规则。

如果你对于模型绑定(Model Binding)的理解也跟我一样还不是很清楚,也没有必要着急,更不要放弃对MVC的学习,因为书的后面章节会有详细的讲解 ,呵呵。现在我们先将ASP.NET MVC的实现放到一边,单纯思考下领域建模(Domain Modelling),下面使用.net和sql server创建一个简单的竞拍程序的领域模型。

一,创建一个简单的领域模型

下面是要创建的竞拍程序的类图


上面的模型包含了一个Members的集合,每一个Member会有一个Bids集合,每一个Bid对应一个Item,每一个Item可以有多个来自不同Members的Bids

实现我们自己的domain model并作为一个独立的组件其中一个关键的地方是我们选择的语言和术语,这个不是我们的编程语言,而是领域建模的通用的语言。这种语言是开发人员和领域的专业人员都知道的,这样主要是为了这两种人能流畅的交流,而这却是至关重要的。当领域的专家们不了解建模的一些概念时,我们应该针对使用的术语达成一个共识,这个共识就是创建一种通用的语言并贯穿在整个领域建模过程中。这样做有很多的好处。

1.首先,开发人员倾向于使用编程语言,比如类名,数据库等等名词来表达。而业务专家们是不懂这些的,他们也不需要懂。业务专家知晓一些技术方面的知识是一件非常危险的事情,因为他们会经常根据自己对技术的理解来不断筛选他们的需求,这也就意味着需求会频繁的更改,进而导致开发人员也不知道业务专家的真实需求到底是什么。创建通用语言的方法能够帮助我们避免在一个应用程序里面过度的泛化需求,程序员倾向于建立每一个可能业务实际模型,而不是具体到某一个业务需求。

2.在通用语言和领域模型之间的这种连接不应该是非常肤浅的而是向DDD(Domain-Driven Design)专家所建议的那样:对通用语言的任何变化都会导致Model的变化。假如我们让建模跟业务领域不同步,我们就需要建立一种从Model到domain映射的中间语言,从长远来看,这种做法会导致灾难。为此,我们将创建一个会两种语言的特殊人类,他们随后就开始筛选需求,这却是建立在他们对两种语言都不完全理解的基础之上,当然这样的后果可以想象。

二,聚合与简化

上面的图,为我们提供了一个很好的建模起点
但是上面图示的模型并没有提供用C#和SQL Server实现Model的任何有用的帮助,会有不少的问题困扰我们:

1.如果我们load一个Member进入内存,也是不是应该load Member的Bids以及相关的Items进入内存呢?

2.如果我们这样做了,我们是否需要将这个Item其他的bids也load进内存,并且也将做这些Bids的Members一同load进内存呢?

3.当我们删除一个对象时,我是否应该删除相关的对象呢?如果是,又有哪些呢?

4.如果我们选择用文档存储代替关系型数据库来持久化,那哪一个对象的集合应该呈现到同一个文档呢?

所有以上的问题,我们不知道作何解答,并且我们的领域模型也没有给我们任何答案。

回答这些问题的DDD方式是将Domain Objects分配到组里面,这种方式称为聚合(aggregates)。

下图很好的展示了怎样聚合在我们这个竞拍程序里面的领域模型,如下所示:


一个聚合的实体组将若干领域对象联合(Together)到了一起,有一个根实体被用来标识整个聚合,它在验证和持久化操作里面充当了"boss"的角色。在数据变化时,我把聚合当作一个单元来统筹处理,所以我们需要创建呈现在领域模型上下文里面有意义的关系的聚合,并且创建跟实现业务过程一致的逻辑操作。也就是说,我们需要通过分组对象来创建聚合,而这些对象是可以作为一个组被改变的。

一个非常重要的DDD规则是,在一个聚合实例范围外的对象,只能通过对根实体(root entity)的引用来持久化,而不是引用在聚合里面的对象。这条规则强化了将聚合里面的对象作为一个单元来对待的概念。在本例子里面,Members和Items都是聚合的根,而Bids只能在作为它们聚合根实体的Item的上下文(the context of Item)里面被访问。Bids可以引用Members(根实体),但是Members不能引用Bids(不是根实体)

聚合的一个好处是简化了对象跟领域模型之间的关系,通常这样能够帮助我们对需要建模的领域的本质的理解。本质上讲,创建聚合约束领域模型和对象之间的关系使得这种关系更加接近于现实领域里面存在的关系。下面是用C#来表达的,如下所示:

public class Member {
public string LoginName { get; set; } // The unique key
public int ReputationPoints { get; set; }
}
public class Item {
public int ItemID { get; private set; } // The unique key
public string Title { get; set; }
public string Description { get; set; }
public DateTime AuctionEndDate { get; set; }
public IList<Bid> Bids { get; set; }
}
public class Bid {
public Member Member { get; set; }
public DateTime DatePlaced { get; set; }
public decimal BidAmount { get; set; }
}

从上面的代码可以看出,我们很容易就捕捉到了Bids和Members之间的单向关系的本质,当然我们也可以建立一些其他的约束。例如:Bids是不可变的,这也是符合实际的。应用聚合能够帮助我们建立更加有用,更加精确的领域模型,也能够让我们用C#熟练的实现。

一般来讲,聚合为一个领域模型增加了结构化和精确化。这也使得应用验证变得容易(根实体负责验证聚合里面所有对象的的状态),这很明显也是持久化的单元。由于聚合的本质就是领域模型的原子单元,它们也能够适用事务管理的单元和级联从数据库删除的单元。

另一方面,聚合常常是人为加上限制。聚合(Aggregates)的概念能够很自然的从文档型数据库得到,但它不是sqlserver本身的概念,也不是存在大部分ORM工具里的概念,为了很好的实现它们,我们的团队需要科学有效的沟通。

三,定义仓库(Defining Repositories)

在某些时候,我们需要给领域模型添加持久化,这通常是通过关系型,对象型,或文档型的数据库来做。持久化不是我们领域模型的一部分,它是一个独立的关注点,这也就意味着我们不能将持久化的代码跟定义领域模型的代码混合到一起。解决这个问题通常的方式就是定义一个仓库(Repositories)

Respositories是基于数据库(可能你选择的是文件存储等等)层面的对象呈现。领域模型通过调用定义在Repositories的方法来间接的存储和查询数据库,这使得我们的Model可以独立于持久化的实现。这样约定就是为每一个聚合(Aggregates)定义单独的数据模型。在我们的竞拍程序里面,我们可以创建2个Repositories,它们分别是针对Members的Repository和针对Items的Repository。注意这里,我们并不需要创建针对Bids的Repository,因为Bids会作为Items聚会持久化的一部分)。

下面是定义的两个Repositories,如下所示:

public class MembersRepository {
public void AddMember(Member member) { ... }
public Member FetchByLoginName(string loginName) { ... }
public void SubmitChanges() { ...}
}
public class ItemsRepository {
public void AddItem(Item item) { ...}
public Item FetchByID(int itemID) { ... }
public IList<Item> ListItems(int pageSize,int pageIndex) { ...}
public void SubmitChanges() { ... }
}

特别需要注意:Repositories仅仅针对Loading和Saving Data.它们不包含任何其他的逻辑。

今天的笔记做到这里,我也是刚学习MVC,做笔记是为了巩固和加深理解,当然如果能给到那些跟我一样的初学者一点点的帮助,我就非常高兴了。笔记里面肯定会有我理解不对的地方,还请路过的大牛们多多帮助指导。谢谢!
祝路过的朋友工作顺利!

晚安!

转载于:https://www.cnblogs.com/mszhangxuefei/archive/2011/12/04/mvcnotes_4.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380053.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一步一步学pwntools(适合新手)

序 pwntools是一个二进制利用框架。官方文档提供了详细的api规范。然而目前并没有一个很好的新手教程。因此我用了我过去的几篇writeup。由于本文只是用来介绍pwntools使用方法&#xff0c;我不会过于详细的讲解各种二进制漏洞攻击技术。 Pwntools的“Hello World” 栈溢出无…

标志寄存器:CF、PF、AF、ZF、SF、TF、DF、OF

注&#xff1a;下面说到的标志寄存器都是缩写&#xff0c;C就是CF&#xff0c;其他也一样 标志寄存器&#xff1a;C、P、A、Z、S、T、D、O的内容只会是0或1&#xff0c;0表示假&#xff0c;1表示真 O&#xff1a;溢出标志 一个寄存器如果存放的值超过所能表示的范围&#xf…

Firefox2狂占CPU解决办法

https://images.cnblogs.com/cnblogs_com/Tisty/138006/o_firefox3.jpg 看了一下&#xff0c;不知道 "jpeg_free_large" 是干啥的&#xff0c;遂用 "Firefox jpeg_free_large" Google 一下&#xff0c;出来的一堆东西里有帖子说可能和 Apple 的 QuickTime …

PUSHAD和POPAD,以及PUSHA和POPA

PUSHAD PUSHAD也叫保护现场&#xff0c;就是把我们的寄存器压入栈中 pushad是把eax&#xff0c;ecx&#xff0c;edx&#xff0c;ebx&#xff0c;esp、ebp&#xff0c;esi&#xff0c;edi依次压入栈中&#xff0c;ESP会减少32&#xff0c;相当于&#xff1a; push eax push ec…

MOVSX和MOVZX

MOVSX 先符号扩展,再传送 格式&#xff1a; MOVSX 操作数A &#xff0c;操作数B //操作数B的空间小于A比如说我们使用命令&#xff1a; movsx eax&#xff0c;bxbx是16位&#xff0c;eax是32位&#xff0c;传值过程&#xff1a; 先用bx的符号位把eax高16填满&#xff0c;b…

LEA与XCHG

LEA 格式&#xff1a; LEA 通用寄存器 内存地址功能&#xff1a;取地址命令 将内存地址赋值给寄存器 lea eax,dword ptr ds:[ecx0x16]dword 双字 就是四个字节ptr pointer缩写 即指针ds 数据段版寄存器[]里的数据是一个地址值&#xff0c;这个地址指向一个双字型数据 将dwo…

ADC和SBB命令

ADC 带进位加法指令 用法&#xff1a; adc 操作数1&#xff0c;操作数2相当于&#xff1a; 操作数1操作数2进位标志CF->操作数1现在的eax是0&#xff0c;C1&#xff0c;用adc指令直接会是0x6 SBB 带进位减法指令 用法&#xff1a; sbb 操作数1&#xff0c;操作数2相当…

mul和div指令(8位,16位,32位)

MUL 无符号乘法指令&#xff0c;默认操作数与eax相乘&#xff08;这里只说32位&#xff0c;其他与下面的div类似&#xff09; 格式&#xff1a; mul 操作数 //操作数只有一个操作数与eax相乘&#xff0c;结果共有16位&#xff08;这里的16位是16进制数&#xff09;&#xff…

imul和idiv指令

imul 有符号乘法指令&#xff0c;分单操作数&#xff0c;双操作数和但操作数 单操作数&#xff1a;此形式与mul指令使用完全相同&#xff0c;操作数乘以al、ax、或eax寄存器中的值&#xff0c;乘积分别存储到ax、dx&#xff1a;ax或edx&#xff1a;eax中 执行指令&#xff1a…

Ajax的注册应用

最近发现Ajax在用户注册表单和用户登录表单方面应用&#xff0c;最能体现Ajax的交互特点&#xff0c;因此又是写了一个习作&#xff01; 演示效果 新开窗口地址&#xff1a; http://www.klstudio.com/demo/ajax/reg.htm 下载地址:http://www.klstudio.com/demo/ajax/reg.rar &…

XADD和NEG命令

XADD 交换相加指令&#xff0c;先交换然后相加 比如说&#xff1a; xadd eax&#xff0c;ecx /* 相当于&#xff1a;先执行&#xff1a;xchg eax,ecx然后执行&#xff1a;add eax,ecx */此时eax2&#xff0c;ecx3&#xff0c;执行完&#xff1a;eax5&#xff0c;ecx2 neg …

Java——File类

一&#xff0c;File类的概述和构造方法 A&#xff1a;file类的概述 file类可以理解成一个路径 文件夹或者是文件夹路径 路径分为绝对路径和相对路径 绝对路径是一个固定的路径&#xff0c;从盘符开始 这里的G&#xff1a;\TIM 就是一个绝对路径&#xff0c;是一个固定的路…

vue3 配置 @符号

config,ts 配置 有 爆红 安装 npm install 一下 然后 配置 路径提示功能 tsconfig.json 配置 路径提示功能 一共这两个路径配置

mts模式_MTS的完整形式是什么?

mts模式MTS&#xff1a;Microsoft Transaction Server /移动电话服务/多通道电视声音 (MTS: Microsoft Transaction Server/ Mobile Telephone Service/ Multichannel Television Sound) 1)MTS&#xff1a;Microsoft Transaction Server (1) MTS: Microsoft Transaction Server…

Java——IO流

一&#xff0c;IO流常识 Ⅰ&#xff0c;IO流的概述 1&#xff0c;IO流用来处理设备之间的数据传输 2&#xff0c;Java对数据的操作都是通过流的方式 3&#xff0c;Java用于操作流的类都在IO包中 4&#xff0c;流 按流向分为&#xff1a; ①输入流 ②输出流 5&#xff0…

《软件》2011年第6期刊登出 《DB 查询分析器》中断SQL语句的执行

《软件》编辑部寄来了2011年第6期样刊&#xff0c;在2011年第6期&#xff0c;刊登出了本人的论文------“《DB 查询分析器》中断SQL语句的执行”。 论文刊登在第42页&#xff0c;排在第13篇&#xff0c;还比较靠前&#xff0c;呵呵。 在“万方数据”和“中国期刊全文数据库”中…

ret2libc过地址随机化

程序&#xff1a; #include<stdio.h> char buf2[10] "this is buf2"; void vul() {char buf1[10];gets(buf1); } void main() {write(1,"sinxx",5);vul(); }很明显&#xff0c;gets函数存在溢出 编译&#xff1a; gcc -no-pie -fno-stack-protect…

远控免杀专题(29)-C#加载shellcode免杀-5种方式(VT免杀率8-70)

0x00 免杀能力一览表 几点说明&#xff1a; 1、表中标识 √ 说明相应杀毒软件未检测出病毒&#xff0c;也就是代表了Bypass。 2、为了更好的对比效果&#xff0c;大部分测试payload均使用msf的windows/meterperter/reverse_tcp模块生成。 3、由于本机测试时只是安装了360全家…

WPF界面设计技巧(2)—自定义漂亮的按钮样式

上次做了个很酷的不规则窗体&#xff0c;这次我们来弄点好看的按钮出来&#xff0c;此次将采用纯代码来设计按钮样式&#xff0c;不需要 Microsoft Expression Design 辅助了。 首先打开 Microsoft Visual Studio 2008 &#xff0c;新建一个WPF项目&#xff0c;在上面随便放几个…

ropgadgets与ret2syscall技术原理

程序&#xff1a; #include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <sys/syscall.h> void exploit() { system("/bin/sh"); } void func() { char str[0x20]; read(0,str,0x50); } int…