Business Objects - 容器还是功能?

时间:2009-11-25 02:23:48

标签: language-agnostic business-objects data-transfer-objects

在我工作的地方,我们多次在这个问题上来回走动,正在寻找理智检查。这里的问题是:Business Objects应该是数据容器(更像是DTO)还是应该包含可以在该对象上执行某些功能的逻辑。

示例 - 获取客户对象,它可能包含一些常见属性(Name,Id等),客户对象是否还包含函数(Save,Calc等)?

一种推理方法是将对象与功能(单一责任主体)分开,并将功能放在业务逻辑层或对象中。

另一条推理说,不,如果我有一个客户对象,我只想打电话给Customer.Save并完成它。如果我正在使用该对象,为什么我需要知道如何保存客户?

我们的最后两个项目已将对象与功能分开,但在新项目上再次提出了争论。哪个更有意义?

修改

这些结果与我们的辩论非常相似。对一方或另一方的一票完全改变了方向。还有其他人想加2美分吗?

修改

尽管答案抽样很小,但似乎大多数人认为业务对象中的功能是可接受的,只要它很简单,但持久性最好放在单独的类/层中。我们试一试。感谢大家的投入......

8 个答案:

答案 0 :(得分:10)

对象是状态和行为。如果某个对象具有明智的行为(例如,计算一个人从出生日期开始的年龄,或者一个发票的总税额),请务必添加它。仅仅是DTO的业务对象被称为“贫血领域模型”。我不认为这是设计要求。

持久性是一种特殊的行为。我称之为“明智”的是商业行为。业务对象不需要知道它是持久的。我会说DAO可以将持久性与业务行为分开。我不把“保存”放在“明智”类别中。

答案 1 :(得分:9)

业务对象可以使用业务功能

持久性不是业务功能,而是技术实现。

长话短说:

  1. 保存/更新/删除/查找等 - 远离持久层中的业务对象。
  2. CalculateSalary,ApplyDiscount等是与业务相关的方法,可以是:
    1. 业务对象的方法(因此BO是实体的自包含表示)或;
    2. 单独服务实施特定功能(因此BO更像DTO)。
  3. 至于第2点 我应该提一下,方法2.1倾向于使BO太过膨胀,违反SRP 。 2.2引入了更多维护复杂性

    我通常在2.1和2.2之间平衡,这样我就可以将与数据相关的琐碎事情放到Business Objects中,并创建更复杂的服务(如果有超过4行代码) - 使它成为一项服务)。

    这将Business Objects的范例转换为更多的数据传输对象。

    但这一切都使项目更容易开发,测试和维护。

答案 2 :(得分:4)

无论平台或语言如何,答案都是一样的。这个问题的关键在于对象是否应该能够自主,或者是否更好地将任何给定的行为分散到具有更强集中责任的对象中。 / p>

对于每个班级,答案可能会有所不同。我们最终得到了一个频谱,我们可以根据责任密度来安排课程。

                          (Level of responsibility for behavior)
         Autonomy - - - - - - - - - - - - - - - - - - - Dependence  
      High
  C      -   <<GOD object>>                            <<Spaghetti code>>
  l      -
  a      -  
  s      -                                      
  s      -                 
         -                        
  s      -  
  i      -  
  z      -
  e      -  <<Template>>                                <<Framework>>
       low  

假设您喜欢让班级自己执行所有行为,或者尽可能多地执行。从该图的左侧开始,当您使类更自主时,类的大小将会增长,除非您不断重构它以使其更通用。这会导致模板。如果没有进行重构,那么这个阶段就会变得更加“像神一样”,因为如果它需要一些行为,它就有了一个方法。领域和方法的数量不断增长,很快变得无法管理和不可避免。由于班级已经做了这么多,编码员宁愿增加怪物而不是试图将它分开并切断戈尔迪结。

图表的右侧具有在很大程度上依赖于其他类的类。如果依赖性级别很高但个别类很小,则表示框架;每个类都没有做太多,需要很多依赖类才能完成某些功能。另一方面,一个高度依赖的类也有大量代码,这表明该类充满了 Spaghetti

这个问题的关键是确定你在图表上感觉更舒服的地方。在任何情况下,除非应用某些组织原则,否则各个类最终会在图表上展开,这就是如何实现模板框架的结果。

刚写完之后,我会说课堂规模和组织程度之间存在关联。 Robert C. Martin(或“Uncle Bob”)在他关于Design Principles and Design Patterns的非常详尽的论文中提到了与包依赖相似的基础。 JDepend是第26页图表背后的想法的实现,是对static analysis toolsCheckstylePMD的补充。

答案 3 :(得分:2)

我认为业务对象知道如何“处理”自己更有意义,然后必须将这种负担放在系统的其他地方。在您的示例中,对我来说,处理客户对象的方法是处理如何“保存”客户数据的最合理的位置。

这可能是因为我认为数据库是“数据容器”,所以我赞成“业务对象”是保护数据容器免受直接访问的更高级别,并强制执行有关的标准“业务规则”如何访问/操纵数据。

答案 4 :(得分:2)

我们多年来一直使用Rocky Lhotka的CSLA框架,并喜欢它的设计方式。在该框架中,所有功能都包含在对象中。虽然我可以看到将逻辑分开的价值,但我认为我们不会很快摆脱这种理念。

答案 5 :(得分:1)

业务对象应该是封装由该对象建模的业务实体的数据和相关行为。可以这样想:面向对象编程的一个主要原则是封装数据和相关行为。

持久性不是建模对象的行为。如果业务对象是持久性的,那么我发现开发进展更加顺利。如果业务对象与底层管道没有特别关联,那么开发新代码和单元测试新代码会更快,更顺畅。这是因为我可以模拟这些方面而忘记了必须通过箍来到达数据库等。我的单元测试将更快地执行(如果你有成千上万的自动化测试与每个构建一起运行,这是一个巨大的优势)和我由于数据库连接问题,我不会因测试失败而受到更少的压力(如果您经常脱机或远程工作并且无法始终访问您的数据库,那么很好,哦,顺便说一句,那些方面(数据库连接等)应该在别处测试!)。

  

另一条推理说,不,如果我有一个客户对象,我只想打电话给Customer.Save并完成它。如果我正在使用该对象,为什么我需要知道如何保存客户?

知道CustomerSave方法已经知道如何保存客户对象。您没有通过在业务对象中嵌入该逻辑来避免此问题。相反,您已经使代码库更加紧密耦合,因此难以维护和测试。推迟将对象持久化到其他人的责任。

答案 6 :(得分:0)

Business Objects,因为它们被命名,显然应该保留自己的业务逻辑,即服务层中域之间业务逻辑的动态。

另一方面,BO可以是数据容器(DTO?)的组成和方法;意思是BO是纯粹的功能吗?这可以避免BO和DTO之间的所有转换。

答案 7 :(得分:-1)

在MVC架构中,

我们可以说Model包含业务对象。