论坛首页 Java企业应用论坛

请问领域对象的setXXX方法是否可以包含业务逻辑?

浏览 3199 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-04-19  
例如这样一个示例class:

public class BudgetItem implements Serializable{
    private double sum;  // 预算金额
    private boolean calculated; // 计算状态位,false表示当前节点没有计算过
    /** 当预算金额被改变,计算状态位应该被设为false */
    public void setSum(double sum) {
        if (this.sum != sum) {
            this.sum = sum;
            this.calculated = false;
        }
    }
}


我疑惑的地方在于,setter是否应该尽量简单化?setSum()应该写成:
public class BudgetItem implements Serializable{
    private double sum;  // 预算金额
    private boolean calculated; // 计算状态位,false表示当前节点没有计算过

    public void setSum(double sum) {
        this.sum = sum;
    }

    public void setCalculated(boolean calculated) {
        this.calculated = calculated;
    }
}


但如果这样的话,用户修改预算项的金额就变成不是原子操作了,如果某个程序员忘记setCalculated就会造成bug。
   发表时间:2007-04-19  
这个问题的核心我认为是数据的冗余,如果无冗余,那么每次取得sum都是即时计算出来的,而不是缓存的sum属性,这样就不存在这个问题了。
如果有缓存,那么就需要额外的同步处理,那么应当仔细设计getter,setter里的逻辑。
你这样处理的方法细节上没有什么问题,关键是整体上是否合理。
0 请登录后投票
   发表时间:2007-04-19  
谢谢你的答复,:D,一针见血。
对,sum属性是故意冗余的,因为费用项可以是树形结构,例如举一个不算太合适的例子:

项目成本
├─差旅费
│ ├─交通费
│ │ ├─汽车
│ │ ├─轮船
│ │ └─飞机
│ └─住宿费
└─加班费

如果通过即时计算的话,在树的层次比较深的时候,顶层节点getSum()的效率会比较低,而且往往读取比写入的需求更多,所以用了一个sum属性来缓存各个节点的金额。

写到DAO的时候,突然想到,如果Hibernate都是通过setter对对象各个属性赋值,万一setter中含有一些比较复杂的业务逻辑的话(例如再调用另一个对象的某个方法),那就会乱套了……

所以我才回头考虑,我这样把业务逻辑放在setter中,是不是一种错误的方向。:-)
0 请登录后投票
   发表时间:2007-04-19  
  这样的冗余字段应该类似中间结果的东西,也是不用持久化的吧?那么如果是一个transient的属性,针对它做一些业务操作即使调用其他对象的一些方法应该也没什么问题吧。
  只是一直习惯将这样的业务写在service层,做好了才赋给模型。现在领域模型不再简单的当做一个实体对象来用,可以包含与该类对象密切相关的业务,举个例子,我们常用的权限控制,就拿User用户这个类来说,判断该用户有什么权限可以认为是和用户密切相关的业务操作,也是它应该具有的方法,如果是以前做肯定是User里就是只有get/set方法,在service里写一个hasPrivilege(user, privilege)的方法,但是现在就可能直接在user里写个hasPrivilege(privilege),针对的当然就是此时的User对象。
  什么是对象本身应该具有的方法,什么不是,什么业务可以在领域对象里写,什么不可以?还真是不好区分啊。
0 请登录后投票
   发表时间:2007-04-19  

我写了很多这样的代码....

在set方法里写一些对属性的非null过滤等控制很方便.

0 请登录后投票
   发表时间:2007-04-19  
codeutil 写道

我写了很多这样的代码....

在set方法里写一些对属性的非null过滤等控制很方便.

这样情况确实有见到过...但是我不知道能不能对程序产生什么影响呢>?
0 请登录后投票
   发表时间:2007-04-19  
sunsy 写道
  这样的冗余字段应该类似中间结果的东西,也是不用持久化的吧?


  o(∩_∩)o...哈哈!!!一语惊醒梦中人,你这句我刚才反复想了很久,的确,冗余属性未必就要持久化。我的目的只是为了减少计算次数而已。
  比较了一下,如果将sum持久化,我会因为某个叶子节点的更新而引发一堆节点的更新,效率降低更多,得不偿失。确实是存在一种中间的解决方法。thank u!

  关于“什么业务可以在领域对象里写,什么不可以”,我做下来感觉还好,主要归功于原先syan老大教导有方,:D
  主要是要脱离开发环境去考虑,也就是抽出来的Domain模型应该是适用于任何语言的,用delphi开发也好,用java开发也好,C/S架构也好,B/S架构也好,都是不变的,就像这个sum属性一样,在单机软件的环境下,它一定是需要持久化的,而在分布式环境下,它就不应该持久化,但不论实现如何,领域模型是不会变的,也许这就是领域模型带给我们的业务框架重用。

  Robbin的这个帖子说的是很棒,但我觉得领域模型尤其不要和分层技术混在一起考虑,因为分层模型是技术上的一种模式,而领域模型表达的是业务对象之间的一些关联,这个时候我们应该是业务专家,先不考虑任何技术的把业务模型搭出来,然后再考虑什么要分离到Service层,一般来说,对一批Domain Object的操作都可以分离到Service层。
0 请登录后投票
   发表时间:2007-04-19  
  呵呵,看来我的胡言乱语有时还是有点用处的啊。领域对象的概念也都基本明白了,不过现在在开发中基本还是把CRUD这样的操作分离出对象来做,今后要更多的考虑下自身相关业务的处理。
0 请登录后投票
论坛首页 Java企业应用版

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