论坛首页 Java企业应用论坛

贫血模型or充血模型新的解决办法

浏览 15246 次
精华帖 (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的帽子来做事情。

先写到这里,大家如果有什么看法敬请拍砖,别投隐藏就行  第一次发帖照顾下吧(我这可是逃课发的帖子)



   发表时间:2011-09-07  
麻烦楼主先把超链接改正确,回了帖慢慢看
0 请登录后投票
   发表时间:2011-09-07  
mlc880926 写道
麻烦楼主先把超链接改正确,回了帖慢慢看


哦 不好意思,url填写错了。不知道系统自动会添加一个“http://”
0 请登录后投票
   发表时间:2011-09-07  
似乎有点意思,希望楼主能给出Java代码。
0 请登录后投票
   发表时间:2011-09-07  
zt122583 写道
似乎有点意思,希望楼主能给出Java代码。

呵呵,给不了java代码啊,java没这个特性。要不我就不用去学Ruby了。我开始学习Ruby就是因为它有这个特性。Scala这个语言也可以。Ruby这个语言真的很好
0 请登录后投票
   发表时间:2011-09-07  
这是损失了多少倍性能换来的呢?
0 请登录后投票
   发表时间:2011-09-07  
lance4t 写道
这是损失了多少倍性能换来的呢?

性能这种东西我不太了解,但是我感觉比较虚。开始的时候不需要考虑的吧?

可伸缩性是和性能是此消彼长的。我感觉这么做比较值得,当出现性能问题的时候再去解决被。

这是我的浅见,我也没开发过大型的项目,目前还在学校混呢 哪位大牛出来给解释下吧。
0 请登录后投票
   发表时间:2011-09-08  
呃,性能是架构设计的时候就要考虑好了的,每个架构都有其性能峰值,软件的确需要良好的伸缩性,但那是对程序员而言,对用户来说,良好的性能及用户体验才是王道。这是一个取舍的问题,这也是为什么架构师如此吃香的原因所在!
0 请登录后投票
   发表时间:2011-09-08   最后修改:2011-09-08
把数据与操作这些数据的逻辑封装到一处,就离OO越来越近了。

领域模型的起点可能有点高,如果能实践当然最好;
贫血模型的起点低些,先不需考虑理想状态,抓住最主要的问题即可:消除重复的代码,
遇到重复的代码至少先封装到一个地方,然后再其它地方调用,
其次再看封装后的代码所应该待的地方,是应该仍待在服务层,还是移到模型层,或者是提炼出一个帮助类将其它放置在其中。
0 请登录后投票
   发表时间:2011-09-08  
晕了 这都隐藏 下回是没分发帖子了 谁能给我个理由为什么隐藏啊 以后我好改改啊
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics