【问题标题】:How to separate interface from implementation in Grails services?如何在 Grails 服务中将接口与实现分开?
【发布时间】:2011-06-19 20:51:43
【问题描述】:

我想知道是否可以在 Grails 上创建服务接口,但我找不到合适的方法。 这种解释并不令人满意,因为它似乎混合了 Java 和 Groovy:

http://www.grails.org/doc/latest/guide/8.%20The%20Service%20Layer.html

鉴于接口机制是 Java(以及大多数 OO 语言)的最佳特性之一,在我看来,这似乎是框架的一个糟糕的设计缺陷。

有什么想法可以澄清这个问题吗?

谢谢! 木龙

【问题讨论】:

标签: grails interface groovy service


【解决方案1】:

你可以有一个接口,但实际上你不需要一个。如果我对您的理解正确,您希望有两种服务实现,并能够选择使用哪一种。

只需实现两个服务,例如MyService1MyService2,然后在grails-app/conf/spring/resource.groovy 中指定:

beans = {
    ... 
    // syntax is beanId(implementingClassName) { properties }
    myService(MyService1)
    ...
}

甚至:

beans = {
    ...
    if (someConfigurationOption) {
        myService(MyService1)
    } else {
        myService(MyService2)
    }
}

这就是你告诉 Spring 为myService 实际注入哪个服务的方式。现在您将可以使用myService 喜欢:

public MyController {
    def myService
    ...
}

Spring 会自动连接一个正确的实现。这允许您根据某些配置来配置要使用的服务实现。

【讨论】:

    【解决方案2】:
    • 在类com.mycompany.mypackage.MyInterface.groovy中定义服务接口存储under src/groovy
    • 定义存储在grails-app/services下的服务实现

      class MyService implements MyInterface {
          // service implementation goes here
      }
      

    【讨论】:

    • 但在这种情况下,我可以在控制器“def myInterface”中指定吗?注射效果如何?
    • 不,你应该声明def myService
    • 依赖注入如何知道你想在控制器中注入哪个实现?正如 tim_yates 所说,你必须通过命名来告诉它。在运行时,您可以获取另一个 bean 引用来实现您的接口并将其分配给 myService,因此可以使用相同的方法。
    • @IslamMuhammad 是的,您可以依赖注入 applicationContext bean,并获取所有类型的实例的所有 bean
    • @IslamMuhammad 我从未测试过这是否适用于 Grails
    【解决方案3】:

    这不是设计缺陷。 Groovy 与 java 的不同之处在于它是一种使用“duck-typing”的动态语言。 groovy 中有趣的是也有接口。因此,如果您遵循@don 的建议,您可以确保您的服务符合接口,但您使用 grails 进行 DI 的方式只是指定服务实现。即你没有得到编译时检查在哪里你使用服务实现,就像你在java中做的那样。

    请注意,这里没有紧密耦合。耦合意味着某些东西被绑定到一个类型。但是使用 groovy 的松散类型系统,类型本质上是动态的生物。所以在java中,如果你声明一个类型是一个特定的实现,如果你以后改变类型,代码可能无法编译。在 groovy 中,如果您使用 'def',代码将始终编译...(我认为这是正确的)

    【讨论】:

      【解决方案4】:

      我为此找到的最佳解决方案是使用 Spring bean 别名。基本上你需要:

      1) 在 src/groovy (MyService.groovy) 中创建接口

      2) 在需要的地方注入服务:

      class MyController {
          MyService myService
      }
      

      3) 创建实现该接口的常规服务(ImplOneService.groovyImplTwoService.groovy

      4) 在 resources.groovy 中添加一个条目,您可以在其中定义要使用的实现(最终,测试环境或您需要的任何其他内容):

      beans = {
          if (...development, useFTP, etc...) {
              springConfig.addAlias 'myService', 'ImplOneService'
          } else {
              springConfig.addAlias 'myService', 'ImplTwoService'
          }
      }
      

      Complete sources here

      我的 cmets:在 groovy 中使用接口确实看起来像是某种“我想坚持使用一些我更熟悉的 java 东西”。在这种情况下,强类型。但这正是 groovy 说的“不用担心,如果你愿意,你可以保持 Java 方式”的美妙部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-18
        • 1970-01-01
        相关资源
        最近更新 更多