How do you share common methods in different grails controllers?

后端 未结 5 1633
南笙
南笙 2020-12-13 01:39

Currently when I need to share a method like processParams(params) between different controllers, I use either inheritance or services. Both solution has some

相关标签:
5条回答
  • 2020-12-13 01:40

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

    0 讨论(0)
  • 2020-12-13 01:47

    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.

    0 讨论(0)
  • 2020-12-13 01:54

    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.
    0 讨论(0)
  • 2020-12-13 02:00

    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]
    }
    
    0 讨论(0)
  • 2020-12-13 02:06

    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()
        }
    }
    
    0 讨论(0)
提交回复
热议问题