




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
好久没有写文章了,最近比较忙,另一方面也是感觉自己在这方面没什么实质性的突破。但是今天终于感觉自己小有所成,有些可以值得和大家分享的东西,并且完成了两个可以表达自己想法的Demo。因此,趁现在有点时间,是写文章和大家分享的时候了。首先给出这两个Demo的源代码的压缩包的下载地址,因为之前有博友说他没有装VS2010而没办法运行Demo,所以这次我分别用VS2008和VS2010实现了两个版本。/netfocus/DCIBasedDDD.rar下面先分享一下我最近研究的一些知识及我对这些知识的自我感悟,然后再结合Demo中的示例讲解如何将这些感悟应用到实际。一.理论知识:我最近一直在学习下面这些东西: 面向对象分析与设计,即Object Oriented Analysis and Design(OOAD) 领域驱动设计,即Domain Driven Design(DDD) 四色原型:MI原型、Role原型、PPT原型、Description原型 DCI架构:Data Context Interaction CQRS架构: 命令查询职责分离原则,即Command Query Responsibility Segregation通过学习以上这些知识,让我对面向对象的分析、设计、实现有了一些新的认识。1. 碰到一个业务系统,我们该如何分析业务,分析需求,并最后得到一个只包含业务概念的模型?答案是通过四色原型进行业务建模。四色原型的中心思想是:一个什么什么样的人或组织或物品或地点以某种角色在某个时刻或某段时间内参与某个活动。 其中“什么什么样的”就是DESC,“人或组织或物品或地点”就是PPT,“角色”就是Role,而”某个时刻或某段时间内的某个活动就是MI。更具体的说明请参看我之前整理的一篇文章:/netfocus/archive/2011/03/05/1971899.html2.业务模型建好了,该如何通过面向对象的分析与设计方法来进行对象建模呢? DDD和DCI思想可以帮助我们。首先,DDD能够指导我们建立一个静态的领域模型,该领域模型能够清楚的告诉我们建立出来的对象“是什么”,但是DDD却不能很自然的解决“做什么”的问题。大家都知道DDD在对象设计的部分实际上是一种充血模型的方式,它强调对象不仅有属性还会有行为,如果行为是跨多个领域对象的,则在DDD中用领域服务解决。但是DDD却没有完整的考虑对象与对象之间的交互如何完成,虽然它通过领域服务的方式协调多个对象之间进行交互或者在应用层协调多个对象进行交互。但是在DDD中,对象往往会拥有很多不该拥有的属性或行为。在我学习了DCI架构之后,我认识到了DDD的很多不足。以下是DCI的核心思想: 对象扮演某个角色进入场景,然后在场景中进行交互,场景的参与者就是对象所扮演的角色; 一个对象可以扮演多个角色,一个角色也可以被多个对象扮演; 对象的属性和行为分为:A:核心属性和行为,这些属性或行为是不依赖于任何场景的;B: 场景属性和行为,对象通过扮演某个角色进入某个特定场景时拥有的属性或行为,一旦对象离开了这个场景,不再扮演了这个角色后,这些场景属性或行为也就不再属于该对象了;比如人有核心的属性和行为:身高、体重、吃饭、睡觉,然后当人扮演教师的角色在教室里上课时,他则具有上课的行为,一旦回到家里,就又变成了一个普通的人;比如一个物品,在生产时叫产品,在销售时叫商品,坏了的时候叫废品,它在不同阶段扮演不同的角色所具有的属性是不一样的; 场景的生命周期,场景是一个时间与空间的结合,可以理解为某个活动;一旦活动结束,则场景也就消失; DCI中的D可以理解为DDD中的领域模型;场景中交互的是角色,而不是领域实体。场景属于DSL的思考层面,更接近于需求和用例。而领域也是伟大的出现,但是不能为了领域而领域,为什么呢?因为场景是大哥用例是大哥。领域的存在是为了控制固定概念的部分,这样在某种成度上控制了一定的复杂性和提高了可控性,而DCI则解决了可变性和需求的问题。从某种意义上来说,“领域层(在DCI中可能不会太凸显领域层,不如OLD DDD那么凸显)” 是为了DCI架构服务的。 角色是人类的主观意识,用于对象分析和设计阶段,但是在运行阶段,角色和对象实体是一体的,软件运行过程中只有对象,只是这些对象在参与某个活动时扮演了某个角色而已;3. 领域驱动设计中的对象设计部分的一些要点: DDD的在对象设计方面的最大贡献之处在于其实体、值对象,以及聚合边界的三个部分,通过这三个概念,我们可以将对象的静态结构设计好。 领域对象所包含的属性必须是只读的,只读的含义是一旦对象被创建好,则只有对象自己才能修改其属性,属性的类型可能是基本数据类型或值类型,即ValueObject; 领域模型设计时不应考虑ORM等技术性的东西,而应该只专注于业务,不要让你的领域模型依赖于技术性的东西; 领域对象的属性和方法设计时要完全根据业务的含义和需要来进行,不要动不动就把每个属性定义为get;set,这会导致领域模型的不安全; 仓储(Repository)不是解决让领域模型不依赖于外部数据存储的唯一方式,我觉得还有更优雅的方式那就是事件驱动; 设计领域模型时不要考虑分层架构方面的东西,因为领域模型与分层架构无关; 不要认为领域模型可以做任何事情,比如查询。领域模型只能帮你处理业务逻辑,你不要用它来帮你做查询的工作,那不是它擅长的领地,因为它的存在目的不是为了查询;CQRS的思想就是指导我们:命令和查询因该完全分离,领域模型适合处理命令的部分,而查询可以用其他任何的不依赖于领域模型的技术来实现,甚至可以直接写SQL也可以; 分析领域模型及其对象之间的交互时,要分清什么是交互的参与者,什么是交互的驱动者,通常情况下,比如人是交互的驱动者,而人在系统中注册的某个帐号所扮演的角色就是交互的参与者;比如我用A的图书卡去图书馆借书,则我是借书活动的驱动者,而A的图书卡对应的帐号所扮演的借书者(Borrower)角色就是借书活动的参与者;二.结合Demo讲解如何将理论应用到实际:前面的介绍看起来比较枯燥,但对我来说是非常宝贵的经验积累。下面我通过一个例子分析如何运用这些知识:以图书管理系统中的借书和还书的场景进行说明:1. 借书场景:某个人拿着某张借书卡去图书馆借书;2. 还书场景:某个人拿着某张借书卡去图书馆还书;根据四色原型的分析方法,我们可以得出:某个“人”以图书借阅者的角色向图书馆借书。从这里我们可以得出三个角色:1)借阅者(Borrower);2)被借的图书(BorrowedBook);3)图书馆。那么这三个角色的扮演者对象是谁呢?其实这是问题的关键!1)是谁扮演了借阅者这个角色?很多人认为是走进图书馆的那个人,其实不是。人所持的图书卡对应的那个人才是真正的借阅者角色的扮演者;试想张三用李四的图书卡借书,借书的是谁?应该是李四,此时相当于李四被张三操控了而已;当然这里假设图书馆不会对持卡人和卡的真正拥有者进行身份核对。所以,借阅者角色的扮演者应该是借书卡对应的帐号(借书卡帐号本质上是某个人在图书馆里系统中的镜像)。那么图书卡帐号和借阅者角色有什么区别?图书卡帐号是一个普通的领域对象,只包含一些核心的基本的属性,如AccountNumber,Owner等;但是Borrower角色则具有借书还书的行为;2)是谁扮演了被借的书这个角色?这个问题比较好理解,肯定是图书了。那图书和被借的图书有什么区别吗?大家都知道图书是指还没被借走的还是放在书架上的书本,而被借的书则包含了更多的含义,比如被谁借的,什么时候借的,等等;3)为什么图书馆也是一个角色?图书馆只是一个地点,它不管有没有参与到借书场景中,都叫图书馆,并且它的属性也不会因为参与到场景中而改变。没错!但是他确实是一个角色,只不过它比较特殊,因为在参与到借书场景时它是“本色演出”,即它本身就是一个角色;举两个其他的例子你可能就好理解一点了:比如教室,上课时是课堂,考试时是考场;比如土地,建造房子时是工地,种植粮食时是田地,是有可能增加依赖场景的行为和属性的。有了场景和角色的之后,我们就可以写出角色在场景中交互的代码了。我们此时完全不用去考虑对象如何设计,更不用考虑如何存储之类的技术性东西。因为我们现在已经清晰的分析清楚1)场景参与者;2)参与者“做什么”;代码如下,应该比较好懂:/借阅者角色定义/publicinterfaceIBorrower:IRoleIEnumerableBorrowedBooksget;/借了哪些书voidBorrowBook(Bookbook);/借书行为BookReturnBook(UniqueIdbookId);/还书行为/图书馆角色定义/publicinterfaceILibrary:IRoleIEnumerableBooksget;/总共有哪些书BookTakeBook(UniqueIdbookId);/书的出库voidPutBook(Bookbook);/书的入库/被借的书角色定义/publicinterfaceIBorrowedBook:IRoleBookBookget;/书DateTimeBorrowedTimeget;/被借时间/借书场景/publicclassBorrowBooksContextprivateILibrarylibrary;/场景参与者角色1:图书馆角色privateIBorrowerborrower;/借书参与者角色2:借阅者角色publicBorrowBooksContext(ILibrarylibrary,IBorrowerborrower)this.library=library;this.borrower=borrower;/启动借书场景,各个场景参与者开始进行交互/publicvoidInteraction(IEnumerablebookIds)foreach(varbookIdinbookIds)borrower.BorrowBook(library.TakeBook(bookId);/还书场景/publicclassReturnBooksContextprivateILibrarylibrary;privateIBorrowerborrower;publicReturnBooksContext(ILibrarylibrary,IBorrowerborrower)this.library=library;this.borrower=borrower;publicvoidInteraction(IEnumerablebookIds)foreach(varbookIdinbookIds)library.PutBook(borrower.ReturnBook(bookId);接下来考虑角色扮演者如何设计与实现:角色扮演者就是DDD中的领域对象,在这个例子中主要有:借书卡帐号(LibraryAccount)、书本(Book)、图书馆(Library);下面是这几个实体类的实现:publicclassLibraryAccount:Object#regionConstructorspublicLibraryAccount(LibraryAccountStatestate):this(newUniqueId(),state)publicLibraryAccount(UniqueIdid,LibraryAccountStatestate):base(id,state)#endregionpublicstringNumberget;privateset;publicstringOwnerNameget;privateset;publicclassBook:Object#regionConstructorspublicBook(BookStatestate):this(newUniqueId(),state)publicBook(UniqueIdid,BookStatestate):base(id,state)#endregionpublicstringBookNameget;privateset;publicstringAuthorget;privateset;publicstringPublisherget;privateset;publicstringISBNget;privateset;publicstringDescriptionget;privateset;publicclassLibrary:Object, ILibraryprivateListbooks=newList();publicLibrary(LibraryStatestate):this(newUniqueId(),state)publicLibrary(UniqueIdid,LibraryStatestate):base(id,state)if(state!=null&state.Books!=null)this.books=newList(state.Books);MannualpublicIEnumerableBooksgetreturnbooks.AsReadOnly();publicBookTakeBook(UniqueIdbookId)varbook=books.Find(b=b.Id=bookId);books.Remove(book);returnbook;publicvoidPutBook(Bookbook)books.Add(book);以上几个实体类还有很多细节的东西需要说明,但暂时不是重点。大家可以慢慢体会为什么我要这样设计这些类,比如属性为什么是只读的?好了,理论上有了角色扮演者、角色,以及场景后,我们就可以写出借书和还书的完整过程了。代码如下:privatestaticvoidBorrowReturnBookExample()/创建图书馆varlibrary=newLibrary(null);Repository.Add(library);/创建5本书varbook1=newBook(newBookStateBookName=C#高级编程,Author=JhonSmith,ISBN=56-YAQ-23452,Publisher=清华大学出版社,Description=Averygoodbook.);varbook2=newBook(newBookStateBookName=JQueryInAction,Author=JhonSmith,ISBN=09-BEH-23452,Publisher=人民邮电出版社,Description=Averygoodbook.);varbook3=newBook(newBookStateBookName=.NETFrameworkProgramming,Author=JhonSmith,ISBN=12-VTQ-96786,Publisher=机械工业出版社,Description=Averygoodbook.);varbook4=newBook(newBookStateBookName=ASP.NETProfessionalProgramming,Author=JimGreen,ISBN=43-WFW-87560,Publisher=浙江大学出版社,Description=Averygoodbook.);varbook5=newBook(newBookStateBookName=UMLandDesignPattern,Author=CraigLarmen,ISBN=87-OPM-44651,Publisher=微软出版社,Description=Averygoodbook.);Repository.Add(book1);Repository.Add(book2);Repository.Add(book3);Repository.Add(book4);Repository.Add(book5);/将这5本书添加进图书馆library.PutBook(book1);library.PutBook(book2);library.PutBook(book3);library.PutBook(book4);library
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 老年人贫血教学课件
- 轻松学会独立思考
- 老年人日常护理课件
- 老年人心态课件
- CN120209385A 一种反射隔热节能型亚克力板及其制备方法
- CN120204939A 高压高湿膜分离测试系统及方法
- 水的组成-2023学年九年级化学上册课后培优分级练(人教版)原卷版
- 人教版高中英语必修三词汇表默写
- 老年专业知识和技能培训课件
- 配饰鉴赏课件
- 2023年起重机械检验员资格考核试题及答案
- 消化科临床重点专科建设项目申报汇报课件
- 新版仁爱九年级下册单词
- 天然气管道泄漏检测技术研究
- 《均衡价格理论》课件
- 动漫手办制作课
- 《现代控制理论》(刘豹-唐万生)
- 《中国居民膳食指南》
- 食品包装用纸盒企业标准
- 供货的合同的范例
- 旧变压器移位专项方案
评论
0/150
提交评论