Подтвердить что ты не робот

Как вы используете общие методы в разных контроллерах Grails?

В настоящее время, когда мне нужно использовать метод типа processParams(params) между разными контроллерами, я использую либо наследование, либо службы. Оба решения имеют некоторые неудобства:

  • С наследованием вы не можете использовать множественное наследование, а это значит, что вам нужно иметь все методы утилиты контроллера в одном месте. Кроме того, есть ошибка в grails, которая не обнаруживает никаких изменений кода в классах базового контроллера в режиме разработки (вам нужно перезапустить приложение).
  • С помощью служб у вас нет доступа ко всем инъецированным свойствам, таким как params, session, flush...

Итак, мой вопрос: есть ли другой способ использовать некоторые распространенные методы, доступные для нескольких контроллеров?

4b9b3361

Ответ 1

Один из вариантов, который мне нравится, заключается в том, чтобы писать общие методы как категорию, а затем при необходимости смешивать их с контроллерами. Это дает гораздо большую гибкость, чем наследование, имеет доступ к таким файлам, как params, и код прост и понятен.

Вот крошечный пример:

@Category(Object)
class MyControllerCategory {
    def printParams() {
        println params
    }
}

@Mixin(MyControllerCategory)
class SomethingController {

    def create = {
        printParams()
        ...
    }

    def save = {
        printParams()
    }
}

Ответ 2

Это не поможет вам перезапустить процесс разработки, но это так, как я решил эту проблему. Это уродливая и, вероятно, не очень хорошая практика, но я ставлю общий код на классы как закрытие. Тогда я могу сделать что-то вроде:

new ControllerClosures().action(this)

а с помощью в классе controllerClosures

def action={
    it.response.something
    return [allYourData]
}

Ответ 3

Общая функциональность - это вызов нового класса, не обязательно общего предка. В формулировке вопроса отсутствует выражение об ответственности за него. Само собой разумеется, это единственная ответственность, за которую мы создаем новый класс. Я принимаю дальнейшие решения на основе ответственности класса.

Я предпочитаю гибрид ответов robbbert и Jared: я создаю дополнительные классы, передавая им необходимые внутренние элементы контроллера в качестве параметров. Иногда классы развиваются из объектов метода. Как:

def action = {
  def doer = SomeResponsibilityDoer(this.request, this.response)
  render doer.action()
}

Не так кратковременно, но позволяет получить код в тестах и ​​поддерживать связь на низком уровне.

Поскольку SomeResponsibilityDoer будет только иметь пару полей - запросить ответ - это не большая сделка, строящая его с каждым запросом.

Это также не имеет большого значения, когда SomeResponsibilityDoer не перезагружается при смене контроллера в dev, потому что:

  • Изначально вы можете объявить его в некоторых файлах Controller - он будет перезагружен. После того, как вы закончите его, мы надеемся, что он не изменится часто, поэтому переместите его на src/groovy.
  • Еще важнее то, что быстрее и лучше разрабатывать дизайн при модульных тестах, чем при запуске приложения и перезагрузке Contoller.

Ответ 4

Вы можете использовать шаблон дизайна делегирования:

class Swimmer {
    def swim() { "swimming" }
}

class Runner {
    def run() { "running" }
}

class Biker {
    def bike() { "biking" }
}

class Triathlete { 
    @Delegate Swimmer swimmer
    @Delegate Runner runner
    @Delegate Biker biker
}

def triathlete = new Triathlete(
    swimmer: new Swimmer(),
    runner: new Runner(),
    biker: new Biker()
)

triathlete.swim()
triathlete.run()
triathlete.bike()

В случае контроллера назначьте вспомогательный класс непосредственно в поле экземпляра (или в конструкторе с нулевым значением):

class HelperClass {
    def renderFoo() { render 'foo' }
}

class FooController {
    private @Delegate HelperClass helperClass = new HelperClass()

    def index = { this.renderFoo() }
}

Информация типа delegate скомпилируется в содержащий класс.

Ответ 5

Вы можете написать общий метод в commonService и использовать эту службу для вызова метода commmon.