Как вы разделяете общие методы в разных контроллерах Grails? - PullRequest
26 голосов
/ 16 ноября 2010

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

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

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

Ответы [ 5 ]

22 голосов
/ 16 ноября 2010

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

Вот небольшой пример:

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

@Mixin(MyControllerCategory)
class SomethingController {

    def create = {
        printParams()
        ...
    }

    def save = {
        printParams()
    }
}
3 голосов
/ 23 ноября 2010

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

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

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

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

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

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

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

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

new ControllerClosures().action(this)

а из с в контроллере класса Closures

def action={
    it.response.something
    return [allYourData]
}
2 голосов
/ 16 ноября 2010

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

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() }
}

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

1 голос
/ 14 мая 2013

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

...