1

Let's say I have an interface with some methods, like this:

interface Task {
    void before();
    void doStuff();
    void after();
}

Here I would implement part of it:

abstract class PoliteTask implements Task{

    @Override
    public void before() {
        System.out.println("Hey");
    }


    @Override
    public abstract void doStuff();


    @Override
    public void after() {
        System.out.println("Cya");
    }

}

Now I want to make sure that those before() and after() implementations are called in all extending classes.

Here we have a class that needs to init something in before():

class ActualStuffTask extends PoliteTask {

    private int fancyNumber;


    @Override
    public void before() {
        // init some things
        fancyNumber = 42;
    }


    @Override
    public void doStuff() {
        System.out.println("Look, a number: "+fancyNumber);
    }

}

Obviously, ActualStuffTask overrides before(), hence it does not say "Hey", only "Cya".

If I made the methods in PoliteTask final, this wouldn't happen, but then it's child classes could not override the methods.

Calling super.before() in the ActualStuffTask would work, but I want to have this effect guaranteed, regardless of child class implementation.

The question is:

What pattern should I use to have both parent implementation, and child implementation?

MightyPork
  • 18,270
  • 10
  • 79
  • 133
  • 1
    Have you considered just using `super.before()` in the child implementation? – Jeroen Vannevel Dec 06 '13 at 22:22
  • @JeroenVannevel The API can't be dependent on the implementation of children. – MightyPork Dec 06 '13 at 22:27
  • Then you'll have to let go of the interface in your baseclass and name the methods differently. You can just make the ones to be implemented `abstract` and call them from the (differently named) ones in your baseclass. – Jeroen Vannevel Dec 06 '13 at 22:28

4 Answers4

5

I like to use abstract methods which you implement in the implementation classes.

abstract class PoliteTask implements Task{

    @Override
    public final void before() {
        System.out.println("Hey");
        doBefore();
    }

    protected abstract void doBefore();
    protected abstract void doAfter();

    @Override
    public abstract void doStuff();


    @Override
    public final void after() {
        System.out.println("Cya");
        doAfter();
    }

}

class ActualStuffTask extends PoliteTask {
    private int fancyNumber;

    @Override
    protected void doBefore() {
        // init some things
        fancyNumber = 42;
    }


    @Override
    public void doStuff() {
        System.out.println("Look, a number: "+fancyNumber);
    }


    @Override
    protected void doAfter() {
        // something else
    }
}

Notice that the Task methods are final. They don't need to be. It depends how you are building your API.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Yeah, I use this too.. I just wanted to find a cleaner, universal solution - read: without changing of the abstract signature. – MightyPork Dec 06 '13 at 22:30
  • @MightyPork You don't have to change the signature. Sub classes of `PoliteTask` already have implemented it. – Sotirios Delimanolis Dec 06 '13 at 22:31
  • I guess this is the real answer. I'd like to keep the same names for the methods, but apparently I can't have it all. – MightyPork Dec 06 '13 at 22:37
  • @MightyPork You do keep the same method names. Since `ActualStuffTask` is a `PoliteTask`, you can call `before()` on a variable of type `ActualStuffTask`. The call will go through `before()` implemented in `PoliteTask` and invoke `doBefore()` implemented in `ActualStuffTask`. – Sotirios Delimanolis Dec 06 '13 at 22:38
  • Yeah I know, I meant for those that you can implement in the child class. To inherit JavaDoc, for example. – MightyPork Dec 06 '13 at 22:39
  • @MightyPork They already do inherit javadoc. You just can't supply new one (without overriding). – Sotirios Delimanolis Dec 06 '13 at 22:41
  • That's not what I meant, you have some javadoc on `before()`, and then make it final and create `doBefore()`. Extending class has `doBefore()`, but without the JavaDoc which was on `before()`. I'm not sure if there's a way to "include" the javadoc. – MightyPork Dec 06 '13 at 22:46
  • @MightyPork Not as far as I know :(, but you can [`@link` and `@see`](http://stackoverflow.com/questions/3618185/how-can-a-methods-javadoc-be-copied-into-other-methods-javadoc). – Sotirios Delimanolis Dec 06 '13 at 22:50
3

The usual approach for such case is like this (simplified example):

abstract class Base {

    public final void before() {
        System.out.println("Hey");
        doBefore();
    }

    protected void doBefore() {
    }
}

This way base code always will get executed, and subclasses can add their implementation.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
1

You can follow the template method pattern. Create a final method in AbstractClass (say, doAll), that calls the other methods in order:

public final void doAll() {
    before();
    doStuff();
    after();
}

Then you can have before and after also be final methods, so that they will always be executed by subclasses, and their behavior can't be changed.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • This looks like an interesting pattern, but how is `doAll()` called? – MightyPork Dec 06 '13 at 22:29
  • This `doAll()` method would be called as part of its API. Normally you would enforce it by making the other methods `protected`, forcing users to call only the `public` method, but you can't do that here because the other methods are defined in the interface and therefore must be `public`. – rgettman Dec 06 '13 at 22:31
  • Actually now that I thought more about this, I realized it doesn't solve anything, since child classes can't override your final `before()` and `after()` – MightyPork Dec 06 '13 at 22:35
1

One option is to call super.before() in your ActualStuffTask class explicitly:

@Override
public void before() {
    super.before();
    // init some things
    fancyNumber = 42;
}

Another option is to change design of you parent class and "protect" before method with final keyword:

abstract class PoliteTask implements Task {

    @Override
    public final void before() {
        System.out.println("Hey");
        internalBefore();
    }

    protected abstract void internalBefore(); // child class should override this method

    ...

}
hoaz
  • 9,883
  • 4
  • 42
  • 53