How do you share common methods in different grails controllers?

Deadly 提交于 2019-11-28 16:52:33

One option I like is to write the common methods as a category, then mix it into the controllers as necessary. It gives a lot more flexibility than inheritance, has access to stuff like params, and the code is simple and understandable.

Here's a tiny example:

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

@Mixin(MyControllerCategory)
class SomethingController {

    def create = {
        printParams()
        ...
    }

    def save = {
        printParams()
    }
}

Common functionality is a call for a new class, not necessarily common ancestor. The question formulation is missing responsibility statement for it. Needless to say, it's a single responsibility that we create a new class for. I take further decisions basing on class responsibility.

I prefer a hybrid of robbbert's and Jared's answers: I construct extra classes, passing them necessary controller internals as parameters. Sometimes the classes develop from method objects. Like:

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

Not so brief, but lets you get code under tests and keep coupling low.

As SomeResponsibilityDoer is only going to have couple of fields - request an response - it's not a big deal constructing it with every request.

It's also not a big deal having SomeResponsibilityDoer not reloaded on controller change in dev, because:

  1. Initially, you can declare it in some of Controller files - it will be reloaded. After you complete it, hopefully it won't change often, so move it to src/groovy.
  2. Even more important, it's faster and better for design to develop under unit tests than under application running and reloading a Contoller.
Jared

This doesn't help the restarting in development mode issue you have, but it's the way I've solved this problem. It's ugly and probably not good practice, but I factor common code into classes as closures. Then I can do something like:

new ControllerClosures().action(this)

and from with in the controllerClosures class

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

You can use the Delegation design pattern:

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

In case of a controller, assign the helper class directly at the instance field (or in the nullary constructor):

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

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

    def index = { this.renderFoo() }
}

The delegate's type information gets compiled into the containing class.

You can write all the common method in commonService and use that service to envoke commmon method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!