Является ли плохой дизайн для вызова сервисов Grails из объектов домена?
Поскольку я все чаще использую Grails, я нахожу, что пишу код в нескольких контроллерах, который действительно кажется, что он должен быть частью класса домена. Иногда этот код домена содержит вызов класса сервиса. Например, недавно я написал метод домена, который выглядел примерно так:
class Purchase {
// Injected
def paymentService
String captureTransactionId
Boolean captured
// ...
def capture() {
captureTransactionId = paymentService.capturePurchase( this )
captured = captureTransactionId != null
}
Я не чувствую себя откровенно грязным, написав этот код, но я не изучал лучшие методы дизайна в Grails, поэтому мне хотелось получить некоторые мнения.
Ответы
Ответ 1
Я иду туда и обратно с такими вещами. Перед Grails у меня не было проблем с анемичными классами домена и помещением всего в помощников. Большая причина, по которой я часто заканчивал анемичные классы, - это валидация. Просто проверить валидность, длину и т.д. Внутри класса, но уникальность требует проверки базы данных и не относится к классу домена (в приложении, отличном от Grails), поэтому я перенес его в помощника. Теперь у меня есть проверка в двух местах, поэтому я бы консолидировался в помощнике и остался бы с классом только для данных.
Но Grails заменяет необходимость в DAO путем проводки в методах GORM в классах доменов, а также заменяет необходимость в валидаторах, помещая проверку в классы домена. Таким образом, это создает проблемы при принятии решения о том, какая бизнес-логика должна идти в классе домена и что должно быть в сервисе или других вспомогательных сервисах - отличное место для размещения бизнес-логики, которая может потребоваться в методе класса домена или валидаторе.
Да, это не OO-чистый, да, вы создаете цикл (служба вызывает класс домена, а класс домена вызывает службу), нет, это не "путь
Сцепление, подобное этому, затрудняет разделение приложения на компоненты или плагины для повторного использования, но объявление сервисов с помощью "def paymentService" очень помогает, поскольку вы не связаны с именем или реализацией пакета.
Ответ 2
Я не думаю, что классы домена/модели должны вызывать сервисы. Это должно быть наоборот.
Служба может организовать другие службы для выполнения прецедента. Я думаю, что правильный путь.
Ответ 3
Я только даю свое личное мнение. Поскольку grails автоматически поддерживает инъекционные услуги в классах доменов (в отличие от, например, инъекционных услуг в стандартные классы groovy, которые вы должны настроить самостоятельно), я бы предположил, что он предназначен для использования таким образом и, следовательно, не является плохой практикой.
Также он делает код более читаемым с чем-то вроде "myDomainInstance.someUsefulMethod()", чем "someService.someUsefulMethod(myDomainInstance)" (надеюсь, вы знаете, что я имею в виду).
Ответ 4
Я не уверен, правильно это или нет.
В таких случаях, как пример, как насчет того или иного пути: либо поставить код paymentService.capturePurchase() внутри класса Purchase, либо вы можете поместить всю логику в службу?