Friday, 25 March 2016

Groovy - A Dynamic Language (Part 2)

Now in this episode we will see a little interesting approach demonstrating the dynamic behaviour of Groovy.

The Objective will be to implement Delegation Design Pattern using Composition rather than inheritance which is always considered to be better approach.

Here we have defined Bus, Car, Truck and a Vehicle class.
The Vehicle class has a call to the method vehicleDelegator() defined within an instance block and having a list of delegator classes as parameter,and this method only does all the Magic.

The method call of vehicleDelegator is there, but where is the definition, we have defined it as within the metaClass of Object class, so it will be present in all classes as all class extends Object.

So when we create an instance of Vehicle this method vehicleDelegator() gets called and at the same time it registers a methodMissing() for Vehicle class.

So whenever we call any method of Vehicle class, control goes into methodMissing() which searches for the particular method in each of the classes passed as parameter to the vehicleDelegator() method. If it finds them invokes them, and registers them in the metaClass of the Vehicle class so that if the same method invoked again from Vehicle, methodMissing() is not invoked and if the method as called from Vehicle is not present in any of the delegator classes then Exception is thrown.

This is a beautiful concept of Method Caching, and reveals the Groovy's true dynamism.


class Vehicle {

    {vehicleDelegator Car, Bus, Truck}

    def startUp()
    {
        println "Vehicle StartUp....."
    }
}

class Bus {

    def busOwner(name)
    {
        println "Bus owner is $name"
    }

}

class Car {

    def carOwner(name)
    {
        println "Car owner is $name"
    }

}


class Truck {

    def truckOwner(name)
    {
        println "Truck owner is $name"
    }
}


class MOPSynthesis {

    static main(args)
    {

        Object.metaClass.vehicleDelegator = { Class... delegates ->

            def delegatesObInstances = delegates.collect {
                it.newInstance()
            }

            delegate.metaClass.methodMissing = {     name, methArgs ->
                println "Intercepting Calls to $name with Args $args....."
                def delegator = delegates.find {
                    it.metaClass.respondsTo(it, name, methArgs)
                }
                if (delegator) {
                    delegate.metaClass."${name}" = { Object[] varArgs ->
                        delegator.newInstance().invokeMethod(name, varArgs);
                    }
                    delegator.newInstance().invokeMethod(name, methArgs);
                }
                 else
                    {
                        throw new MissingMethodException(name, delegate.getClass(), args)
                    }

            }
        }

        def vehicle = new Vehicle()
        vehicle.carOwner('Mic')
        vehicle.carOwner('Puchu')
        vehicle.carOwner('Stag!!')

    }
}

View Subhankar Paul's profile on LinkedIn

No comments:

Post a Comment