AweSIM
AweSIM

Reputation: 1703

Java polymorphism and method chaining

So I have a couple of inherited classes defined like so.

class Base {
    public Base chainedMethodA() {
        // some stuff
        return this;
    }
}

class Derived extends Base {
    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
}

Now, the following code works:

Derived obj = new Derived();
obj.chainedMethodB().chainedMethodA();

But this does not (notice the switched order of function calls):

Derived obj = new Derived();
obj.chainedMethodA().chainedMethodB();

The compiler gives an error on the chainedMethodB() function call. I can understand that this is because when you run chainedMethodA(), it returns an object of type Base, which does not have chainedMethodB defined.

I can think of a few solutions to this problem:

  1. Chain methods while paying attention to order (call Derived's methods first, and then call Base's methods). This looks like a very brittle solution.
  2. Override chainedMethodA in Derived so it returns an instance of Derived instead of Base. This looks like a waste of inheritance.

Is there any elegant way around this problem? Maybe some construct that magically changes chainedMethodA to return a Derived instance when called by an object of type Derived, without being explicitly overridden in Derived.

Upvotes: 4

Views: 773

Answers (2)

granmirupa
granmirupa

Reputation: 2790

Override chainedMethodA in Derived so it returns an instance of Derived instead of Base. This looks like a waste of inheritance.

You're wrong. You aren't wasting inheritance.

Technique of overriding is to do just that namely specialize a method. Override can be done when the returned type is the same or a subtype of the return type declared in the original overridden method in the superclass. So in this case you are violating nothing.

Read here for more about overriding.

Here example 1: (calling the superclass method)

public class Derived extends Base {
    @Override
    public Derived chainedMethodA(){

         super.chainedMethodA();
         //some stuff
        return this;
    }

    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
}

Here example 2: (changing it completele)

public class Derived extends Base {
    @Override
    public Derived chainedMethodA(){
        //some stuff
        return this;
    }

    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
    }

Upvotes: 2

cowls
cowls

Reputation: 24354

In this situation inheritance is probably the simplest solution.

However, your last sentence pretty much explains generics:

Maybe some construct that magically changes chainedMethodA to return a Derived instance when called by an object of type Derived, without being explicitly overridden in Derived.

So something like this may be useful in other similar use cases:

static class Base {
    public <T extends Base> T chainedMethodA(Class<T> clazz) throws Exception {
        // some stuff
        return clazz.cast(this);
    }
}

static class Derived extends Base {
    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
}

public static void main(String args[]) throws Exception {
    Derived obj = new Derived();
    obj.chainedMethodA(Derived.class).chainedMethodB();
}

Upvotes: 0

Related Questions