锁定老帖子 主题:贫血模型or充血模型新的解决办法
精华帖 (1) :: 良好帖 (8) :: 新手帖 (0) :: 隐藏帖 (7)
|
|
---|---|
作者 | 正文 |
发表时间:2011-09-07
最后修改:2011-09-08
一个简单例子:贫血模型or领域模型这篇文章,感觉有很多共鸣之处。上面的贫血模型和充血的领域模型,我都遇到过。下面写写我遇到的情况和解决办法吧。
早晨看了首先是贫血模型,大家都知道java是一门面向对象语言,但是什么才是OO,还需要好好考虑考虑。刚开始编程的时候,写出的代码结构基本和贫血模型差不多。首先是一个贫血的model然后是dao和service。现在感觉起来我是在拿一门面向对象的语言来写面向过程的代码。上面一层(service)想要什么数据,下面一层dao给它传递过去。没有一点OO的感觉。 因为这个原因我以前写的代码有很多重复的地方,尤其是get,set方法偏多。 下面说说充血领域模型吧。这个是好东西啊,先推荐两本好书,一本当然是DDD了,另一本书是UML和模式应用。它们都给软件开发与很多指导。 好了现在开始说领域模型,不扯别的了。我认为领域模型的重点就是职责的分配,我们应该把职责分配到领域模型中(UML那本书就给了我们9中指导原则),不应该放在其他的层次。这样在以后业务逻辑在变化的时候,我们就与业务逻辑一起变化我们的代码。这样我们的代码就能实现我与企业共发展的目的:) 但是充血模型就一定好吗?实习的时候,开发过一个进销存系统。项目不算大,但是业务逻辑也不少。我们开始使用充血模型进行开发。但是到后期我发现领域模型中的一个model职责被分配的太多了。即使使用重构等技术,最后model还是很复杂。有时候model里代码多的,我都不想再去看第二遍。 最近偶然的机会找到了我认为比较好的解决办法,不知道企业真实开发的时候是不是这样。下面我就举一个例子,大家来看看是不是一个很好的解决办法:) 这个方法是我在Andrzej Krzywda大牛的博客上找到的。如何你进不去的话,你懂的。我看到他的博客里面基本都是些关于DCI的。于是一篇一篇的看了一下。他博客里面有一个购物的例子,我发现这不就是充血模型的解决之道吗? 提到了DCI,我们就应该用它来和传统的MVC框架比较一下,了解一下各自的优缺点。 大家应该都是用过struts,一个MVC框架。当我们使用这个框架的时候,我们都会把业务逻辑向下移动到model里面,使control里面尽量不要包含业务代码。但是这样会导致一种情况,model层过于肥胖。那么DCI就给了我们一个解决办法。它可以让充血模型减肥。DCI强调数据场景交互。 而且传统的MVC比较死板,而DCI则更加强调场景交互。当我们有一个新的用例,我们直接可以创造新的场景,并让user戴上不同的帽子去工作就可以了。所以DCI更加灵活。 比如我们人,可能在教室里就是学生,在家就是子女。那么我们就可以抽象出来学生和女子这两个角色,同时这两个角色也是在教室和家这个场景中才会有效的。所以我们可以使用DCI来把学习和子女相关的属性和方法提取出来。当人进入到教室这个场景的时候,我们再把这个角色赋予给人。这样原来这个肥胖的人就变得苗条起来。 我们真的了解OO吗?下面给出一段引用Andrzej Krzywda的一段话: One of the things DCI claims is that most of the time we don't do object oriented programming but we do class oriented programming 好了大家应该对DCI有一个初步的印象了。下面我讲列出我写的一个例子。为了和上面引用帖子做对比,我也写了一个转账的例子。 首先我们定义一个账户类: class Account def initialize(username, money) @username = username @money = money end def get_money @money end end 然后定义两个角色,一个是被转账的账户,一个是转账的账户。 module DebitAccount def debit(amount) @money -= amount end end module CreditAccount def credit(amount) @money += amount end end 下面是转账的场景: class TransferContext def execute @debitAccount.debit(@amount) @creditAccount.credit(@amount) end def initialize(debitAccount, creditAccount, amount) @debitAccount = debitAccount @debitAccount.extend DebitAccount @creditAccount = creditAccount @creditAccount.extend CreditAccount @amount = amount end end 不好意思,可能大家对Ruby不是很了解,我也没过多解释。其实重点就是上面这一段代码,它的构造函数接受两个账户和一个转账金额。然后其中有两句是重点@debitAccount.extend DebitAccount和@creditAccount.extend CreditAccount 这两句是使这两个账户分别带上被转入账户和转账账户的帽子,然后去实现职责。 下面是测试程序 gfc_account, lh_account = Account.new("gfc", 3000), Account.new("lh", 2000) transferContext = TransferContext.new(gfc_account, lh_account, 3000) transferContext.execute puts "****工资上交中****" puts "余额为:" + gfc_account.get_money().to_s puts "***************" puts "余额为:" + lh_account.get_money().to_s puts "****上交完成****" 下面是结果: ****工资上交中**** 余额为:0 *************** 余额为:5000 ****上交完成**** 好了所有代码都贴完了,其中没有加入事物和链接数据库的代码,Ruby才开始学,一些语法还不是很了解,先写这么多吧。 代码的解释: 根据四色原型,我们上面写的TransferContext就相当于一个MI,而Account就相当于一个PPT,DebitAccount和CreditAccount就相当于Role。当我们的PPT进入MI这个场景的时候,我们就让他带上DebitAccount的帽子来做事情。 先写到这里,大家如果有什么看法敬请拍砖,别投隐藏就行 第一次发帖照顾下吧(我这可是逃课发的帖子) 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-09-07
麻烦楼主先把超链接改正确,回了帖慢慢看
|
|
返回顶楼 | |
发表时间:2011-09-07
mlc880926 写道 麻烦楼主先把超链接改正确,回了帖慢慢看
哦 不好意思,url填写错了。不知道系统自动会添加一个“http://” |
|
返回顶楼 | |
发表时间:2011-09-07
似乎有点意思,希望楼主能给出Java代码。
|
|
返回顶楼 | |
发表时间:2011-09-07
zt122583 写道 似乎有点意思,希望楼主能给出Java代码。
呵呵,给不了java代码啊,java没这个特性。要不我就不用去学Ruby了。我开始学习Ruby就是因为它有这个特性。Scala这个语言也可以。Ruby这个语言真的很好 |
|
返回顶楼 | |
发表时间:2011-09-07
这是损失了多少倍性能换来的呢?
|
|
返回顶楼 | |
发表时间:2011-09-07
lance4t 写道 这是损失了多少倍性能换来的呢?
性能这种东西我不太了解,但是我感觉比较虚。开始的时候不需要考虑的吧? 可伸缩性是和性能是此消彼长的。我感觉这么做比较值得,当出现性能问题的时候再去解决被。 这是我的浅见,我也没开发过大型的项目,目前还在学校混呢 哪位大牛出来给解释下吧。 |
|
返回顶楼 | |
发表时间:2011-09-08
呃,性能是架构设计的时候就要考虑好了的,每个架构都有其性能峰值,软件的确需要良好的伸缩性,但那是对程序员而言,对用户来说,良好的性能及用户体验才是王道。这是一个取舍的问题,这也是为什么架构师如此吃香的原因所在!
|
|
返回顶楼 | |
发表时间:2011-09-08
最后修改:2011-09-08
把数据与操作这些数据的逻辑封装到一处,就离OO越来越近了。
领域模型的起点可能有点高,如果能实践当然最好; 贫血模型的起点低些,先不需考虑理想状态,抓住最主要的问题即可:消除重复的代码, 遇到重复的代码至少先封装到一个地方,然后再其它地方调用, 其次再看封装后的代码所应该待的地方,是应该仍待在服务层,还是移到模型层,或者是提炼出一个帮助类将其它放置在其中。 |
|
返回顶楼 | |
发表时间:2011-09-08
晕了 这都隐藏 下回是没分发帖子了 谁能给我个理由为什么隐藏啊 以后我好改改啊
|
|
返回顶楼 | |