Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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

    ...

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top