Повторение кода с использованием метода поиска домена Grails

Исходная проблема

Если у вас есть разные методы, которые в основном отличаются только одной строкой, есть ли способ сделать его СУХИМ, создав один метод.

Пример:

def showA( ) {
   def instance

    try {
        instance = A.findById( params.id )
    } catch ( Exception e ) {
        def message = "Error while retrieving details for the given id ${ params.id }, $e"
        log.error message
        responseAsJson( 400, "Invalid id", message )
        return false
    }

    return checkAndRender(instance,  params.id);
}

def showB( ) {

       def instance

        try {
            instance = B.findByBId( params.BId )
        } catch ( Exception e ) {
            def message = "Error while retrieving details for the given id ${ params.id }, $e"
            log.error message
            responseAsJson( 400, "Invalid id", message )
            return false
        }

        return checkAndRender(instance,  params.id);
    }

Итак, есть ли способ создать один метод и просто передать его как параметр:

  • Класс домена
  • идентификатор для поиска

Или было бы лучше вместо этого передать оператор SQL?

Обновлять

Основываясь на комментарии @dmahapatro, я придумал следующее:

def showA( ) {
        def clos = {id -> A.findByAId( id ) }
        return findAndShow(clos, params.AId, params )
    }

def showB( ) {
        def clos = {id -> B.findByBId( id ) }
        return findAndShow(clos, params.BId, params )
    }

 def findAndShow(Closure closure, def id, def p)
    {
        def instance
        try {
            instance = closure(id)
        }
        catch ( Exception e ) {
            def message = "Error while retrieving instance details for the given id ${ id }, $e"
            log.error message
            responseAsJson( 400, "Invalid Id", message )
            return false
        }

        return checkAndRender(instance,  id);
    }

Остались только проблемы:

  • Как очистить еще больше / сделать его чище.
  • #P7# <цитата> #P8#
       def findAndShow(Closure closure, def id, def p)
    

person Menelaos    schedule 03.12.2014    source источник
comment
У вас может быть метод, который принимает замыкание в качестве параметра. Вот так должно работать. Обратите внимание на использование метода tryCatchClosure.   -  person dmahapatro    schedule 03.12.2014
comment
@dmahapatro Это была хорошая идея. Однако я получаю раздражающее предупреждение: The [findAndShow] action in [ApiController] accepts a parameter of type [groovy.lang.Closure]. Interface types and abstract class types are not supported as command objects. This parameter will be ignored. Вопрос об обновлении. def findAndShow (закрытие закрытия, идентификатор защиты, защита p)   -  person Menelaos    schedule 03.12.2014
comment
@dmahapatro Если вы хотите, напишите свой ответ как ответ, чтобы я проголосовал. Спасибо.   -  person Menelaos    schedule 03.12.2014
comment
Сделайте findAndShow защищенным, а не общедоступным, чтобы избавиться от предупреждения.   -  person Gregor Petrin    schedule 03.12.2014
comment
@Грегор Петрин Да, это сработало!   -  person Menelaos    schedule 03.12.2014
comment
Кроме того, чтобы сделать вызывающий код короче, просто сделайте все в закрытии, например. findAndShow { B.findByBId(params.id) } (Groovy неявно возвращает значение последней команды) и try { instance = closure() }   -  person Gregor Petrin    schedule 03.12.2014


Ответы (1)


Первое, о чем вам следует побеспокоиться, если вы хотите получить DRY-код, это определить лучшую обработку исключений. Попытка ловить свой код везде, чтобы обрабатывать ответ клиенту, не очень СУХАЯ, если вы поместите свой код доступа к данным в сервисы, вы можете генерировать исключения из них и использовать глобальный контроллер для перехвата ошибок и обработки ответов. Например:

class ErrorController {

    def serverError() {
         if (request.format == 'json') {
            //Code for handling errors in json request, request.exception stores the data about the exception. 
        } else {
            //Code for handling errors in non-json request, e.g:
            render(view: 'error', model: [msg: 'Something went wrong']) //add an error view for this
        }
    }
}

Если хотите, вы также можете добавить обработчики для других типов ошибок (403, 404 и т.д.)

Добавить в UrlMappings.groovy

    "500"(controller: "error", action: "serverError")

Теперь вы можете реорганизовать свой код, используя новую обработку ошибок и отражение:

Контроллер:

   class MyController {

        def myService

        def show() {
            def result = myService.myFind(params.className,params.id)
            render result as JSON //Render stuff
        }
    }

Обслуживание:

       import grails.util.Holders

       class MyService {

            def myFind(String className, Long id) {
                def result = Holders.getGrailsApplication().getDomainClass('com.mypack.'+ className).findById(id)
                if(!result) {
                    throw new ServiceException('really descriptive and usefull error msg')
                }
            }
        }

Я определил класс ServiceException, поэтому я могу добавить для него пользовательскую логику в моем ErrorController с помощью оператора instanceOf.

person agusluc    schedule 03.12.2014