图书馆惊魂记之一(一个简单的领域模型的建立过程)

在大学里的某一天,一个漆黑的夜晚,我来到了一个学校里阴森的图书馆,虽然说不喜欢,但是为了考试不要零蛋,所以拼死也要温书了。来到图书馆的柜台前,遇到了图书管理员。然后我跟管理员说:“我来借书了”,管理员头也不抬的把手一指:“书架在那边,自己去找”。

--------------------------------------------------------------------------------

image

---------------------------------------------------------------------------------

书架实在是很多,都是分门别类的把书放好在上面的,每个书架上都有标签,标明了这个书架上放的什么类型的书。

---------------------------------------------------------------------------------

image

---------------------------------------------------------------------------------

于是我一排排的在书架上开始浏览有些啥书

---------------------------------------------------------------------------------

image

---------------------------------------------------------------------------------

看到一本还不错的书,我就把书取出来,然后看看书的内容

------------------------------------------------------------------------------------------------

image      image

------------------------------------------------------------------------------------------------

看了看,写的不错,于是拿着这本书去找管理员:“我要借这本啊”。管理员二话没说,拿个本子记下来我借了这本书,然后在书上打个标签

------------------------------------------------------------------------------------------------

image

------------------------------------------------------------------------------------------------

然后我就接到了这本有用地书,然后回去温书考试去了。

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以上的内容只是一个简单例子的模拟,而生成的类图也是很粗略的,我们通过对业务行为的分析(经典的借书过程来分析得到上面的图形-为了简单我直接用了VS的类图,其实不是很规范,有很多建模工具可以使用,领域模型的分析没有一定之规所以可能每个人分析出来的模型并不相同,所以如果你觉得有其他的理由,画成了其他的样子,那是完全合理的),回到主题,我们要通过领域模型来驱动我们的设计,但是,我们要弄明白的是什么是领域模型的分析,适合什么地方,什么时候不适合。

领域模型(Domain Model)是一个商业建模范畴的概念,他和软件开发并无一丝一毫的关系,即使一个企业他不开发软件,他也具备他的业务模型,所有的同行业的企业他们的业务模型必定有非常大的共性和内在的规律性,由这个行业内的各个企业的业务模型再向上抽象出来整个行业的业务模型,这个东西即“领域模型”。一个掌握了行业领域模型的软件公司,根本不需要再给人家开发项目了,根本不需要靠软件开发养活自己了,你光给这个行业的企业提供业务咨询已经赚得非常丰厚的利润了。

由此我们可知,领域模型的分析并不是我们要做这个软件的时候要做的,而是在这个软件所要实现的业务模式出现的时候就可以开始,所以领域建模比较适合需求比较固定,且业务模式比较成熟的领域。我们首先建立起一个领域模型,然后用最简单直接的类去实现这个模型。这个时候我们不涉及数据库以及持久化等等细节,然后对模型进行精化,利用设计模式将类进行分解,将领域模型的类的职责用多个小类来实现。

比如User类,我们可以用Factory模式加上Facade模式把这个类的职能和持久化行为(数据层的行为)解耦。

其实DDD不一定就是代表着臃肿的实体类,而我们很多时候是在自己设计的时候因为对OO和设计模式的运用不够熟练从而设计出了臃肿的实体类(我自己其实也经常弄出这种类出来-不过通过运用设计模式重构,在大多数情况下是可以改变的)。作为一个合格的程序员,能够快速的完成需求是必要的条件。但是如果只是要求能够做出来实现需求,是不是对自己的要求过低了点,我们不光是需要能跑起来的程序,还需要稳定健壮的程序,更甚的是优美的实现程序,如果仅仅是满足于实现需求,借用星爷的一句话:人没有追求,那和咸鱼有什么分别:)

posted on 2007-09-26 00:23 亚历山大同志 阅读(3312) 评论(26) 编辑 收藏

评论

#1楼 2007-09-26 10:00 麒麟.NET      

弱弱的问句:这个类图是用什么工具画的?  回复 引用 查看   

#2楼[楼主] 2007-09-26 10:00 亚历山大同志      

@麒麟.NET
VS2005 TeamSuit 自然,用的盗版的
 回复 引用 查看   

#3楼 2007-09-26 10:06 户籍民警      

啥是優美,多半騙騙老板,大多數程序員寫的東西只有自己看的happy,你看是一朵花,別人看是一跎糞,簡單程序的維護還是依賴規範和透明,還有就是在不是必需的情況下不使用少有人用到的框架  回复 引用 查看   

#4楼 2007-09-26 12:42 徐少侠      

博主好文

看这里的同学们能不能仔细体会了
建议在看的时候,不要老想着每个方法内部如何实现

例如读者的借入书行为和管理员的借出书行为
呵呵,估计很多人都无法顺利实现

因为,他们会这么想啊?
先 User.BorrowBook(Book)
然后在方法内改变Book的属性不就完成了吗?
或者Librarians.LendBook(Book)
然后在方法内改变Book的属性不就完成了吗?

可是两个一起实现该怎么做?
这样?
User.BorrowBook(Book)
{
........
Librarians.LendBook(Book);
...........
}

呵呵,有趣的合理分析,和我们多数人从来没有体验过的编码经验冲突了。
OO的基本思想之一能解决这个实现问题
参考资料:
消息是指对象间相互联系和相互作用的方式。一个消息主要由5部分组成:发送消息的对象、接收消息的对象、消息传递办法、消息内容(参数)、反馈。
更厉害的定义如下:
消息传递是对象之间动态联系的唯一形式,也是计算的唯一形式
 回复 引用 查看   

#5楼 2007-09-26 12:46 徐少侠      

顺便说一下
亚历山大同学阿
你的出发点是好的,叙述是流畅的。
但是正如你所说:以上的内容只是一个简单例子的模拟,而生成的类图也是很粗略的
尤其是我上面提到的东西,如果同时两边有方法,呵呵。其实已经是非常复杂的OO了。比先前的Book.Save更高高深了。因为之前的讨论,我们都不用关心消息机制。
而这两个东西的实现,没有消息机制简直会让OO发疯的

你故意的吧?
 回复 引用 查看   

#6楼[楼主] 2007-09-26 12:58 亚历山大同志      

@徐少侠
先搭个架子再说,已开始就去想到了咋个入库,咋个分页,那就不要分析什么模型了,直接上来就开始写SQL吧。再说我才说到之一,你就又要黄袍加身的要我来解释消息机制,那我又不敢往下写下去了。要知道专门分析Petshop就能写本书出来,而且老是说很多写本书出来都还分析得不够透彻。
我这里的意思就是让大家简单一点来,不要老在分析模型的时候去拿什么细节的实现问题来说事。
还有,模型是可以测试的。经过测试的模型是比较稳固和让人放心的。

同时谢谢你帮我说了我没说的话,不要老一上来就想着如何实现。说白了不管什么事务啊持久化啊还不就是那些东西,常来博客园观摩的同学还怕自己实现不出来么?
 回复 引用 查看   

#7楼 2007-09-26 13:06 徐少侠      

同意

回顾我自己的经验积累
其实让一个程序员不思考实现而直接用类图思考,不是那么容易的事情。
我至少是努力了1-2年才基本做到用模型而不是代码来思考问题。

然后就发现一堆模型等着我去看,怎么以前都不知道有呢?
 回复 引用 查看   

#8楼 2007-09-26 15:15 bluebird      

曾经以为 只有老外有这样的风格,看来我错了,不错。  回复 引用 查看   

#9楼 2007-09-26 15:38 小生      

看來樓主還是沒能真正理解領域模型

在您的類圖中﹐出現了user類﹐而user實際上只是系統的一個外部實體﹐也就是用例(use case)中的actor﹐而不是系統中領域模型的對象。

至于您的Librarian﹐其實剛好瞎貓碰到死老鼠﹐這個Librarian﹐在領域模型中稱為"控制器"﹐也就是代表系統與外部實體和領域模型打交道的對象﹐當然您這里還少了一些方法﹐這些方法與use case的描述相關(見下面的use case場景分析)。

因此才會出現以下2行自相矛盾的代碼﹕
User.BorrowBook(Book)
Librarians.LendBook(Book);

用戶Borrow﹐不就是管理員Lend嗎?它們實際上是user(也就是這個系統實際的使用者)和系統(即域控制對象)共同完成的一幕場景(在系統分析時﹐稱為用例use case)而已。

標准的開發過程﹐在用例分析時﹐會產生一個這樣的use case (借書)

用戶﹕登錄系統
系統﹕顯示所有書架
用戶﹕(瀏覽)選擇一個書架
系統﹕顯示這個書架中具體的書籍
用戶﹕(瀏覽)選擇一本書籍
系統﹕顯示這本書籍的詳細資料
用戶﹕借閱
系統﹕處理借閱﹐記錄相關借閱記錄﹐借出成功

真正實現時﹐系統要new一個控制器對象﹐由這個對象代表系統負責與這個借閱者打交道﹐最終幫助他完成整個借閱過程

借書的aspx.cs代碼

Page_Load事件
Librarians librarian = new Librarians();
librarian.ShowShelves();

在Shelve_Link的Click事件中
librarian.SelectShelve(shelve_id);
librarian.ShowBooks();

在Book_Link的Click事件中
librarian.SelectBook(book_id);
librarian.ShowBookDetail();

在借閱按按的Click事件中
librarian.Lend();

這就是actor和系統的整個交互

而不是您的系統自己new一個user﹐再new一個Librarian﹐然后2個對象互相玩

建議您看一下<UML和模式應用>﹐那確實是一本很好的書(強烈推荐,翻譯得也相當好)﹐相信你在看完后﹐會對領域建模有更深的理解﹐也會使您的面向對象知識更加丰富
 回复 引用 查看   

#10楼[楼主] 2007-09-26 15:54 亚历山大同志      

@小生
我可是一行代码都没有写啊,杂就被你看出这么多细节才该有问题。God。
我用类图来画只是因为没装Visio将就来画画的。以来就望眼欲穿的直达代码

请看看我对领域模型的定义,何为领域,如何建模。再看看DDD,才几句话页面的代码都出来了,我看就是大师也不会这么做的吧
 回复 引用 查看   

#11楼 2007-09-26 16:10 小生      

@亚历山大同志
呵呵﹐借貴地展示一下領域模型開發的過程﹕)

如果其它的文字您覺得"道不同﹐不相為謀"﹐那就算了﹐求同存異嘛。
不過書的推荐倒是可以保留...

 回复 引用 查看   

#12楼[楼主] 2007-09-26 16:16 亚历山大同志      

@小生
个人觉得还是太简单了点,最好是新发个Post。而且最好是看图说话,这样子容易理解,也不会造成还在模型阶段代码都出来了的误会,我主要是画图的的时候图省事没有装Visio或者Rose,直接操起了VS画出来,所以就误会了。
我的看法重点都用红字标出来了:

领域模型的分析没有一定之规所以可能每个人分析出来的模型并不相同

所以你的做法有你的道理。实体该在那里出现,Service该在那里出现,持久化在那里实现,只要不违背OO的原则,不管是贫血还是充血的还是四不像的,都不是什么大问题。有的时候可能你认为多于的做法,在一定的环境下是有道理的。
 回复 引用 查看   

#13楼 2007-09-26 16:39 小生      

@亚历山大同志
呵呵﹐沒關系~ 我也沒看到下面那些文字~

不過還是要謝謝你﹐將OO討論帶入Net社區﹐大家共同進步~
 回复 引用 查看   

#14楼 2007-09-26 17:39 徐少侠      

@小生
小生的功底深厚哦
我觉得亚历山大的这个咚咚应该算静态类分析,希望他不要生气。
不是领域分析
最近几天似乎谈领域的多了起来?精力分散不过去。我还是专注OO和实体框架,其实最后也能殊途同归的。

但是小生提到的一个问题我想再深入一下
就是那个矛盾的两个方法

小生从标准领域模型概念,把亚历山大的图书管理员重定义成了系统。因此你会这么判断
其实如果不和小生的定义一致,比如我们真的要在系统内实现普通的借阅人和具体的图书管理员这么两个角色怎么办?因为图书管理员可能不止一个,需要在进行借阅的时候有着更个性化的行为。
至于是不是领域模型一定要拒绝User的出现,因为不熟悉领域,以后再论把。
 回复 引用 查看   

#15楼 2007-09-26 17:57 小生      

@徐少侠
功底深厚不敢当,也是初入OO大堂,共同进步吧~

比如我们真的要在系统内实现普通的借阅人和具体的图书管理员这么两个角色怎么办?
-----------------------
这句话不是很能理解,如果是一个真实的图书管理系统(也就是进行借书,还书,统计借阅记录),那确实想不出借阅人如何实现,因为每个系统都有一个系统边界,系统在实现的时候只要考虑边界内的东西,而对于边界外的实体,只要提供一个接口,让其访问即可,而这里的借阅人是处于图书管理系统外部的一个实体,所以无法将其在系统中抽象

另外,您说的图书管理员有多个,每个需要个性化的行为,我想您的意思可能是对于金卡会员,可以一次借10本书,而普通会员则一次借一本书的区别吧。

首先是图书管理员这个类,它有一个“借阅”方法,对于简单的借书逻辑,它可以自己直接实现,但是对于比较复杂的借阅逻辑,则可以再通过抽象出对象(如这里可使用策略模式)来完成真正的借阅过程。


 回复 引用 查看   

#16楼 2007-09-26 18:17 徐少侠      

可能没说清楚
每个登录系统的用户,会不会对应有一个实例,来表示他自己?
这个就是我上面说的借阅者,既读者.
如果仅将读者作为一系列数据来处理,就不会有读者类
但是从系统处理角度出发,领域模型里面应该都是对象之间的模型,独立出这个数据读者我觉得比较难理解,想不通啊.

自然,在我们前面讨论的范围内,普通来借书的人是不能使用这套系统的.因此可能不必存在一个类叫来借书的人的,但是程序在处理读者信息的时候,就只能直接面向数据处理了.

而图书管理员作为一个工作人员,肯定是要登录到系统内部的,感觉图书管理员不应该是系统本身.
 回复 引用 查看   

#17楼 2007-09-26 18:31 文渊阁      

楼主同志 能不能给个VS2005 TeamSuit的下载地址。
找了好长时间了。不好找。
 回复 引用 查看   

#18楼 2007-09-26 18:57 小生      

对呀,因为这个系统不直接与读者打交道,所以没有这个读者类。但是有一个借书证的类,标识一个借阅人,您不能限制一个读者只能用一个借书证吧,他也可以办2个借书证,或者他也可以同时拿2个借书证来借书,因此这个系统关注的是借书证,而不是读者,只要将借阅记录与借书证关联即可。借书证编号在借书时,由图书管理员输入或扫描进系统,通过ID获得借书证对象,然后通过借阅记录对象与被借的书对象完成关联,即完成借阅逻辑。

类似的还有“POS系统”,就是超市里收银的那种,顾客拿着商品来到收银台结账,POS系统只接收商品编码和数量,以及打印单据,而不管买东西的是谁。因为系统不关注这些信息,也不需要知道这些信息。

另外一个就是系统操作人员了,如收银员和图书管理员,他们有登录系统,但是如果这个系统的边界就是图书借阅服务,对于图书管理员,是没有必要过度关注的。因此只要在借阅时,将图书管理员的ID传入借阅过程,就可以将借书的管理员信息记录在借阅记录对象中。
 回复 引用 查看   

#19楼[楼主] 2007-09-26 20:11 亚历山大同志      

@徐少侠
@小生
我已经在POST里写得很清楚了的,领域模型的分析是没有常规和一定的对错的,只要符合一定的要求,那么都是有道理的,只是视角不一样而已。
 回复 引用 查看   

#20楼 2007-09-26 23:58 怪怪      

@小生
认同你说的方式.

@亚历山大同志
视角不一样, 但是总会有一个更合适的视角.
 回复 引用 查看   

#21楼[楼主] 2007-09-27 08:43 亚历山大同志      

@怪怪
可以和好的是两个概念,很奇怪的是人们在为了达到强调自己的观点的同时总会模糊自己的取向,比如如果别人说这个好的时候,就会说没有好不好,只有和不合适,其实都可以。但是当别人说都可以的时候就会说虽然都可以,但是肯定有最合适的。怪哉
 回复 引用 查看   

#22楼 2007-09-27 09:17 杨其仲      

@小生
亚Tx 能发出POST来讲述一个东东,这种共享精神是非常值得大家学习的,让我们这些小菜鸟能多学习,接触很多东西. 先不管对错, 这是大家一个理解的过程,我个人认为,我们都能够去其糟粕,取其精华,我每看完一篇有价值的文章,都感觉增长了自己的知识, 感谢乐于无私共享知识的人.
@亚历山大同志
我顶你啊, 虽然有一些无聊的人冒充你,哈哈,不过希望你不要在意啊, 那是他们RP有问题,歇斯底里了, 不用跟他们一般计较,希望你能继续写出更精彩的文章来
 回复 引用 查看   

#23楼 2007-09-27 16:11 GerryJiang      

--引用--------------------------------------------------
麒麟.NET: 弱弱的问句:这个类图是用什么工具画的?
--------------------------------------------------------
Class Designer,vs中的一个很不错的类图工具,虽然功能简单了一些,但是和vs是结合得非常不错的,自动生成代码方面做得也不错,可以把类与类之间的关系表示得很清晰.
 回复 引用 查看   

#24楼 2007-09-27 16:28 GerryJiang      

这篇文章因小生的回复才有价值,小生,你可以完全另发一篇什么文章,放在这个评论里可惜了!  回复 引用 查看   

#25楼 2007-09-27 19:16 张子阳.      

楼主博客排名Top 100了,恭喜一个 ^O^  回复 引用 查看   

#26楼[楼主] 2007-09-27 22:30 亚历山大同志      

因为画图工具的关系,产生了不少误会,所以准备近期将此贴重构一次。  回复 引用 查看   

导航

公告


放一首适合飚车的音乐,听这个开车会不知不觉的加速
昵称:亚历山大同志
园龄:5年
荣誉:推荐博客
粉丝:116
关注:0
<2007年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

统计

搜索

 
 

常用链接

最新随笔

我的标签

随笔分类(128)

随笔档案(134)

相册

朋友的Blog

同事的Blog

积分与排名

最新评论

阅读排行榜

评论排行榜

推荐排行榜