Как отделить интерфейс от реализации в сервисах Grails?

Мне было интересно, возможно ли создать сервисный интерфейс на Grails, и я не могу найти правильный способ сделать это. Это объяснение неудовлетворительное, поскольку, похоже, Java и Groovy:

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

Мне кажется, что я плохой дизайн-фрейм фреймворка, учитывая, что интерфейс-интерфейс является одной из лучших функций Java (и большинства языков OO).

Любая идея прояснить эту проблему?

Спасибо! Mulone

Ответы

Ответ 1

У вас может быть интерфейс, но на самом деле он вам не нужен. Если я правильно вас понимаю, вы бы хотели иметь две реализации службы и иметь возможность выбирать, какой из них использовать.

Просто реализуйте две службы с именем, например, MyService1 и MyService2, затем в 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
    }
    

Ответ 3

Это не дизайнерский недостаток. Groovy отличается от java тем, что это динамический язык, который использует "утиную печать". Что интересно в Groovy, так это то, что существуют также интерфейсы. Поэтому, если вы будете следовать рекомендациям @don, вы можете убедиться, что ваша служба соответствует интерфейсу, но способ, которым вы выполняете DI с помощью grails, - это просто указать реализацию сервиса. то есть вы не получаете проверку времени компиляции, когда используете реализацию службы, как в java.

Обратите внимание, что здесь нет жесткой связи. Связывание подразумевает, что что-то связано с типом. Но при использовании Groovy свободной системы печати типы являются, по существу, динамическими существами. Поэтому в java, если вы объявляете тип конкретной реализацией, код может не компилироваться, если вы позже измените тип. В groovy код всегда будет компилироваться, если вы используете "def"... (я думаю, это правильно)

Ответ 4

Лучшим решением, которое я нашел для этого, является использование Spring bean псевдонимов. В основном вам необходимо:

1) Создайте интерфейс в src/ groovy (MyService.groovy)

2) Внесите свой сервис туда, где вам это нужно:

class MyController {
    MyService myService
}

3) Создайте свои обычные службы, реализующие этот интерфейс (ImplOneService.groovy, ImplTwoService.groovy)

4) Добавьте запись в resources.groovy, где вы определяете, какую реализацию использовать (в конечном счете, тестирование для среды или что-то еще, что вам нужно):

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

Полные источники здесь

Мои комментарии: Использование интерфейсов в groovy действительно кажется каким-то "Я хочу придерживаться некоторых java файлов, с которыми мне больше нравится". В этом случае сильная типизация. Но это точно хорошая часть groovy, говорящая "Не беспокойтесь, вы можете сохранить java-путь, если хотите".