35

好吧,关于 NoSQL 数据库的事务脚本有一个类似的主题,但这个主题是关于一般模式的。从我对事务脚本的发现来看,它根本不是面向对象的。尽管它可以在其代码的每一行中使用对象,但它基本上是程序代码。

更好的解决方案是使用域模型,结合活动记录或具有工作单元/身份映射/延迟加载/查询对象等的数据映射器。事务脚本可能很容易使用,但它实际上是过程式编程,因此应该被视为面向对象世界中的反模式。

你怎么看?你同意事务脚本是反模式吗?或者你真的有办法设计一个面向对象的事务脚本而不是变相的过程?我怀疑这是可能的。

4

3 回答 3

58

事务脚本绝对不是反模式。

从我对事务脚本的发现来看,它根本不是面向对象的。

你是对的,事实并非如此。然而,这一事实并不能使它成为反模式。尽管它是一种过程方法,但实际上,它在一系列业务逻辑架构模式中仍然占有一席之地——你只需要知道在哪种情况下使用它是最佳实践——而在哪种情况下不是。简单地说:如果您的问题域非常简单,那么在您的业务逻辑中使用更复杂的模式是不值得的。

或者——正如福勒所写:

何时使用它

Transaction Script 的荣耀在于它的简单性。以这种方式组织逻辑对于只有少量逻辑的应用程序来说是很自然的,并且它在性能或理解方面的开销很小。

您可能会想到的反模式称为贫血域模型。当您打算认为您正在构建域模型时就是这种情况 - 因为您的问题域已经足够复杂了 - 但实际上您最终会使用事务脚本 - 因为糟糕的代码组织/薄弱的 OO 技能。

于 2013-05-06T14:19:09.877 回答
16

不是反模式。事实上,大多数企业应用程序(我所见过的)都使用事务脚本而不是富域模型模式。

您提到的活动记录模式仅在您拥有相当简单的域实体到持久存储聚合(RDBMS 表)的一对一映射时才会派上用场。

数据映射器类似于 ORM(Hibernate 和朋友)。如果您的业务逻辑驻留在域实体中,则这些实体必须自行变异。在我看来,这将改变状态(使用 ORM 时固有的)与状态本身结合起来的逻辑。从外部查看您的域模型并将您的业务逻辑放入服务(事务脚本)中会更简单。此外,如果您的业务逻辑量很大,那么当它分散在域实体中时(就像将您的事务脚本混合在一起一样),很难找到相关代码。

但是您不必最终采用完全程序化的方法,因为您可以(并且应该)将您的服务分解为自包含的高度内聚的“程序容器”。

于 2013-08-14T12:13:48.563 回答
0

TS 不是 OO 或非 OO。您可以在域模型方法、服务方法或高级应用程序方法中使用它。这只是意味着您可以阅读程序的业务意图,而无需通过一百万个回调和“黑魔法”。

这就是微软引入 async/await 的原因。它将看起来晦涩难懂的 send-a-callback(委托)和 exit,process-the-callback-in-separate-method(必需)样式转换为可读的事务脚本

GOTO 很糟糕,因为它们破坏了事务脚本的可读流程,使其成为一个糟糕的脚本。

a) 事务脚本出错是一种反模式。例如,一个巨大的方法,没有或很少的方法调用等,同一方法中的不同级别的操作(将它们重构为方法)。业务流程的离散步骤集中在一个方法中(将它们分解为方法或单独的类。很多业务对象?使用 DDD 服务模式)。

b) 不正确使用 TS 是一种反模式。例如大量的应用程序间消息传递、事件触发等,因此您无法通读并查看业务流程(技术应用程序的功能要求)。低层次的细节(技术)与功能性工作相结合。过度分离应该在一页上可见的业务活动。

TS 的使用应该是分形的,每次放大都会深入到更详细的 TS 样式逻辑。高级:您会看到方法调用和 DDD 服务使用。中等水平可能有点混合。下面主要是域对象方法/属性调用以及最精细的逻辑细节。

将 TS 扔到公共汽车下,因为它可能会被滥用,或者阻止它的使用,只会把罐子踢到路上 - 无法分组和分离并且不知道 SRP(单一责任)/凝聚力的开发人员会搞砸其他风格, 也。答案是对他们进行业务流程培训,并举例说明分组和分离——这应该通过业务/功能需求(垂直切片)而不是技术(水平切片)来完成。

  1. 将只处理一个域对象或其类型的其他实例的逻辑放在 DO 中。不要从域对象(person.orders)中引用其他对象类型或将任何东西注入到域对象中。(其他 DO 或存储库等)。就这么简单,它违反了 SRP。[方法中的低级事务脚本]
  2. 当你需要 person.orders 之类的东西,或者感觉需要注入一些东西时,创建一个 DDD 服务(不序列化,每次使用后没有持久属性)。注入例如一个人,以及其他集合(存储库或 IQueryable 等)。在那里工作。[此处为中级交易脚本]
  3. 在 DDD 服务的“应用程序方法”类别中组合对域对象和 DDD svcs 的操作。
  4. 从程序的最高级别构造和调用那些

在每个级别,它看起来像一个 TX 脚本,但要遵守规则。保持方法小。到时候你就可以阅读了!

注意:在另一个答案中提供的链接中,Fowler 告诉您如何使交易脚本正确与错误:

https://www.informit.com/articles/article.aspx?p=1398617

他也确实暗示它不是面向对象的。我认为您可以将它与 OO 混合并使用 TS 专业人士(可读性和一百个专业人士),以及数百名 OO 专业人士。也就是说,您可以将TS元素放在一个领域模型中,并在更高层次的TS中组合领域模型的使用。

还要考虑将事务脚本定义为单个数据库事务。由于您的域模型不应该注入存储库(将域对象注入存储库),因此您实际上可以像这样组织它,调用相关存储库以在最高级别(取消)持久化。但如果不是这样,关键是要有一个没有过度分离的可读代码流。

抨击 TS 的问题在于它使人们认为 SRP 完全是关于 SoC(关注点分离),而他们永远不必担心凝聚力(将相同的东西放在一起,这也意味着 SoC,但需要组织)。因此,好心的工程师只是将事物分成一百万个部分(因为越多越好),并且更难辨别逻辑。

于 2020-10-07T17:29:13.110 回答