【问题标题】:What logic should go in the domain class and what should go in a service in Grails?什么逻辑应该放在域类中,什么应该放在 Grails 中的服务中?
【发布时间】:2012-04-04 16:15:56
【问题描述】:

我正在开发我的第一个 Grails 应用程序,其中涉及移植旧的 struts Web 应用程序。有很多现有的功能,当我把东西移过来时,我很难决定什么应该放在服务中,什么应该直接包含在模型中?

来自主要是 Ruby on Rails 开发的背景,我强烈倾向于将几乎所有内容都放在与之相关的领域类中。但是,对于像我要移植的应用程序一样大的应用程序,某些类最终会变成成千上万行。

您如何决定域中的内容与服务中的内容?是否有任何既定的最佳实践?我环顾四周,但大多数人似乎都承认了这个问题。

【问题讨论】:

    标签: oop grails


    【解决方案1】:

    总的来说,我遵循的主要准则是:

    如果一块逻辑与多个领域类相关,则将其放入服务中,否则放入领域类中。

    如果没有更多关于您正在处理的逻辑类型的详细信息,很难更深入地了解,但这里有一些更一般的想法:

    1. 对于与视图呈现相关的内容,这些内容包含在标签库(或者可能是服务)中
    2. 对于处理确定将什么发送到视图以及将其发送到哪个视图的事情,在控制器(或者可能是服务)中进行
    3. 对于与外部实体(即文件系统、队列等)对话的事物,它们进入服务中

    一般来说,我倾向于选择过多的服务而不是过于集中在一起。最后,一切都是关于最有意义的事情,以及您如何看待代码以及您希望如何维护它。

    但是,我要注意的一件事是,您要移植的内容可能存在大量代码重复。由于 Grails 是基于 Groovy 构建的,并且可以访问更强大的编程方法(如闭包),您可能可以清理和简化 大部分代码。

    【讨论】:

    • 发现应该在域中的方法的一个好方法是,如果您有一个方法将域类作为其唯一参数传递,那么该方法可能属于域。我还将扩展@cdeszaq 的答案,并说如果您要处理多个域类的instance,请将其放入服务中。例如,如果您要更改特定类的多个实例,我会将其放入服务中。但总的来说,请使用您的最佳判断,与您的团队讨论您不确定它们属于何处的方法。
    • 只是补充一点,服务方法默认是事务性的:grails.org/doc/latest/guide/…
    【解决方案2】:

    我个人认为这不仅是服务和域类之间的决定,还包括插件或注入代码。

    想想像Book.findAllByName() 这样的动态查找器。 Grails 将它们注入到领域类中真是太好了。否则必须将它们复制到每个域类中,否则它们将可以通过服务调用 (dynamicFinderService.findAllByName('Book') -argh)。

    所以在我的项目中,我有很多东西会转移到插件中并注入到域类中......

    【讨论】:

    • 非常好。特别是对于新的 Grails“转换”,插件看起来有点像一个神奇的黑盒,但它们非常强大,可以大大简化代码。
    【解决方案3】:

    从 Java EE 的角度来看:域类中根本没有逻辑。使您的域类尽可能简单和简短。您的域模型是应用程序的核心,并且必须易于获取。

    • Grails 是为依赖注入而开发的。域类中的所有逻辑都很难测试,也很容易重构。
    • 您不能像与服务 (DI) 一样交换实现。
    • 您无法轻松测试域类的代码。
    • 您无法扩展您的系统,因为您的实现无法像服务一样被池化。

    我的建议:在服务中保留所有逻辑。服务易于测试、易于重用、易于维护、易于重新配置。

    特定于 grails:如果您更改域类,内存中的 DB 将被杀死,因此您会丢失测试数据,这会阻止您进行快速原型设计。

    【讨论】:

    • 您能否详细说明您的答案,并解释您所说的“容易获得”是什么意思以及为什么您认为域类中不应该有任何逻辑?
    • Grails 并没有非常严格地遵循 JEE 模型。验证和 DB 映射绑定到域对象中,因此您已经获得的不仅仅是一个基本的 bean。正如您在此处所建议的那样,我强烈反对 贫血域类,因为它需要更多的类和复杂性而收效甚微。
    • 您对更新提出了一些好处,但您仍然忽略了验证和数据库映射已经绑定到域类的事实。你似乎仍然在提倡贫血的领域课程,我非常反对。也就是说,除了处理域类的单个实例之外,任何逻辑都绝对应该进入服务,部分原因是您提到的一些要点。
    • 一般来说,我将所有会直接影响数据库映射的约束都放入域类中。所有其他类型的验证和约束都进入命令对象,以便以后更加灵活。好吧,我喜欢贫血的领域课程,因为测试就是一切。但是,这可能会受到个人经验的影响。
    • @crudolf - 由于您可以让命令对象复制域对象验证,因此您在这方面将验证排除在域对象之外的论点无效,我不确定如何减少 任何对象本质上只是一个数据结构增加了测试能力,因为测试练习逻辑和一个贫血的领域对象没有逻辑。
    猜你喜欢
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2016-12-18
    相关资源
    最近更新 更多