Как отделить интерфейс от реализации в сервисах 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-путь, если хотите".