11

在我工作的地方,我们已经在这个主题上反复讨论了很多次,并且正在寻找健全性检查。这里的问题是:业务对象应该是数据容器(更像是 DTO)还是应该包含可以在该对象上执行某些功能的逻辑。

示例 - 以客户对象为例,它可能包含一些常见属性(名称、ID 等),该客户对象是否还应包含函数(保存、计算等)?

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

另一种推理方式是,不,如果我有一个客户对象,我只想调用 Customer.Save 并完成它。如果我正在消费对象,为什么我需要知道如何拯救客户?

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

编辑

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

编辑

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

4

8 回答 8

10

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

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

于 2009-11-25T02:28:00.130 回答
9

业务对象可以具有业务功能

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

长话短说:

  1. 保存/更新/删除/查找等 - 远离持久层中的业务对象。
  2. CalculateSalary、ApplyDiscount 等是与业务相关的方法,可以是:
    1. 业务对象的方法(因此 BO 是实体的自包含表示)或;
    2. 实现特定功能的独立服务(因此 BO 更像 DTO)。

至于第2点。
我应该提一下,方法2.1往往会使BO过于臃肿并违反SRP。而 2.2 引入了更多的维护复杂性

我通常在 2.1 和 2.2 之间进行平衡,以便将与数据相关的琐碎事物放入 Business Objects 并为更复杂的场景创建服务(如果有超过 4 行代码 - 使其成为服务)。

这将业务对象的范式转变为更多的数据传输对象。

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

于 2009-11-25T02:44:54.740 回答
4

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

对于每个班级,答案可能不同。我们最终得到了一个范围,我们可以在该范围内根据责任密度放置类。

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

假设您喜欢让班级自己执行所有行为,或者尽可能多地执行。从该图的左侧开始,当您使您的类更加自治时,除非您不断地重构它以使其更通用,否则类的大小将会增长。这导致一个模板。如果不进行重构,则倾向于使该类变得更加“神一样”,因为如果它需要某些行为,它就有一种方法。领域和方法的数量不断增长,很快就变得难以管理和不可避免。由于该课程已经做了很多工作,因此编码人员宁愿增加这个怪物,也不愿尝试将其拆散并切断 Gordian 结。

图的右侧有在很大程度上依赖于其他类的类。如果依赖级别高但单个类很小,那就是框架的标志;每个类都做的不多,需要很多依赖的类来完成一些功能。另一方面,高度依赖的类也有大量的代码,这表明该类充满了Spaghetti

这个问题的关键是确定你在图表上感觉更舒服的地方。无论如何,除非应用了一些组织原则,否则单个类最终会散布在图表上,这就是您如何实现TemplateFramework的结果。

刚刚写完,我想说班级规模和组织程度之间存在相关性。Robert C. Martin(或“Uncle Bob”)在他关于设计原则和设计模式的非常详尽的论文中涵盖了类似的包依赖关系。 JDepend是第 26 页图表背后思想的实现,并补充了静态分析工具,例如CheckstylePMD

于 2009-11-30T22:58:00.537 回答
2

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

于 2010-11-14T13:46:24.870 回答
2

我认为让业务对象知道如何“处理”自己更有意义,然后不得不把这个负担放在系统的其他地方。在您的示例中,对我来说,处理如何“保存”客户数据的最合乎逻辑的地方是 Customer 对象。

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

于 2009-11-25T02:27:10.520 回答
1

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

持久性不是建模对象的行为。如果业务对象不了解持久性,我发现开发进展会更顺利。如果业务对象没有特别绑定到底层管道,则开发新代码和单元测试新代码会更快、更顺畅。这是因为我可以模拟这些方面而忘记必须通过箍来访问数据库等。我的单元测试将执行得更快(如果您有数千个在每个构建中运行的自动化测试,这是一个巨大的优势)而且我压力会更小,因为我不会因为数据库连接问题而导致测试失败(如果您经常离线或远程工作并且不能总是访问您的数据库并且哦,顺便说一下,这些方面(数据库连接等)应该在其他地方进行测试!)。

另一种推理方式是,不,如果我有一个客户对象,我只想调用Customer.Save它并完成它。如果我正在消费对象,为什么我需要知道如何拯救客户?

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

于 2009-11-30T16:29:19.667 回答
0

业务对象,正如它们所命名的那样,显然应该包含它们自己的业务逻辑,域之间的业务逻辑的动态是在服务层中的。

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

于 2010-02-03T03:22:11.137 回答
-1

在 MVC 架构中,

我们可以说模型包含业务对象吗?

于 2010-02-22T12:41:56.563 回答