28

Let's say I have a Java class

abstract class Base {
    abstract void init();
    ...
}

and I know every derived class will have to call init() after it's constructed. I could, of course, simply call it in the derived classes' constructors:

class Derived1 extends Base {
    Derived1() {
        ...
        init();
    }
}

class Derived2 extends Base {
    Derived2() {
        ...
        init();
    }
}

but this breaks "don't repeat yourself" principle rather badly (and there are going to be many subclasses of Base). Of course, the init() call can't go into the Base() constructor, since it would be executed too early.

Any ideas how to bypass this problem? I would be quite happy to see a Scala solution, too.

UPDATE: Here is a generic version of the Factory Method approach:

interface Maker<T extends Base> {
    T make();
}

class Base {
    ...
    static <T extends Base> T makeAndInit(Maker<T> maker) {
        T result = maker.make();
        result.init();
        return result;
    }
}

UPDATE 2: This question is basically "how do you use Template Method for constructors"? And the answer seems to be, "You can, but it's a bad idea". So I can do a Template Factory (Template Method + Abstract Factory) instead.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • 2
    If init() is abstract in the base class, then why does every derived class have to call it? What happens if they don't? – Skip Head May 25 '10 at 17:38
  • 1
    Why don't you call init() in the constructor of the `Base` class? – aioobe May 25 '10 at 17:42
  • @Skip Head: they won't be initialized properly. – Alexey Romanov May 25 '10 at 17:52
  • @aioobe Because it would be run before the constructor of the derived class. And the implementation of `init()` in the derived class may depend on, e.g., fields being already initialized. – Alexey Romanov May 25 '10 at 17:55
  • 1
    @Alexey Romanov: I thought it was an abstract method in the base class. – Skip Head May 25 '10 at 18:15
  • 1
    @Alexey Romanov: I think Skip Head's point is valid. I feel you're doing this to enforce a convention while not really gaining anything else. It doesn't seem to make sense for the base class to have such an abstract method if it's not going to make use of it; just let the derived classes use a helper method as their concrete implementations so require. – Mark Peters May 25 '10 at 18:23

6 Answers6

12

Avoid this. If you do it, any class that extends your DerivedX class may decide to also call init() thus leaving the object in inconsistent state.

One approach is to let the init() method be invoked manually by clients of your class. Have an initialized field, and throw IllegalStateExcepion if any method that requires initialization is called without it.

A better approach would be to use a static factory method instead of constructors:

public Derived2 extends Base {
    public static Derived2 create() {
       Derived2 instance = new Dervied2();
       instance.init();
       return instance;
    }
}

Update: As you suggest in your update, you can pass Builder to a static factory method, which will call the init() on the instance. If your subclasses are few, I think this is an overcomplication, though.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
10

What happens in init()? It's likely that a better design could eliminate the method altogether, or at least relax the requirement that it execute after the sub-class' constructor. Be certain that init() does not make the object under construction visible to any other threads before the constructor completes, because that creates concurrency bugs.

As an (ugly) alternative, an abstract method could be implemented by sub-classes as a pseudo-constructor:

abstract class Base {
  Base() {
    ctor();
    init();
  }
  abstract void ctor();
  abstract void init();
}
erickson
  • 265,237
  • 58
  • 395
  • 493
  • Actually, this looks better than other solutions to me (ugly, but less ugly than alternatives). – Alexey Romanov May 25 '10 at 18:26
  • 2
    It is suicidal solution: https://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors – gavenkoa Feb 11 '19 at 17:57
6

In addition to Bozho's recommendation, an application container is excellent for the task.

Mark your init() method with the javax.annotation.PostConstruct annotation and a rightly configured EJB or Spring container will execute the method after the dependency injections are finished, but before the object can be used by the application.

An example method:

@PostConstruct
public void init() { 
    // logic..
}

In an enterprise application you can open resources to for example the files system in the init() method. This initialization can throw exceptions and should not be called from a constructor.

Community
  • 1
  • 1
Espen
  • 10,545
  • 5
  • 33
  • 39
2

if Java had it, we wouldn't see all these init() method calls in the wild.

"surround child constructor with something" - that cannot be done in pure java. Too bad, because there can be very interesting applications, especially with anonymous class + instance initialization block.

factory and container - they can be helpful when native new doesn't do the job; but that's trivial and boring, and won't work with anonymous classes.

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • Isn't the Container design pattern something in web? Can you give a link to some Java explanation/examples? (I couldn't find anything good on Google). – aderchox Oct 07 '21 at 20:03
1

Or use spring... you can do <beans default-init-method="init">, see Default initialization and destroy methods.

Istao
  • 7,425
  • 6
  • 32
  • 39
1

If you are adverse to using factories for some reason, you could use the following trick:

trait RunInit {
    def init():Unit
    init()
}

class Derived1 extends Base with RunInit {
    def init() = println("INIT'ing!")
}

This will run init() before the Derived1 constructor/body.

Fred Haslam
  • 8,873
  • 5
  • 31
  • 31