1

I have a question about something that maybe not be possible, but it is worth a try.

I have these classes:

Class A {
    private int x = 0;

    public A() {
        afterCreate();
    }

    public void afterCreate() {
        x = 10;
    }

    public int getX() { 
        return x; 
    }
}

Class B extends A {
    public B() {
        super();
        //Do something
        afterCreate();
    }

    @Override
    public void afterCreate() {
        x = 20;
    }
}

Class C extends B {
    public C() {
        super();
        //Do something
        afterCreate();
    }

    @Override
    public void afterCreate() {
        x = 30;
    }
}

As you can see, I need to ALWAYS, automatically call afterCreate() when the constructor ends. But if I just call afterCreate() inside each constuctor, you can see that for an object created from the class C, we will call the method afterCreate() three times (one for each constructor) -- the first two calls being useless.

Also, I can't call afterCreate() just in the first constructor, because afterCreate() MUST be executed after the last constructor.

Class A {
    public A() {
        //Do something
        afterCreate();
    }
}

Class B extends A {
    public B() {
        super();
        //Doing something that I missed to process in afterCreate()!
    }
}

Class C extends B {
    public C() {
        super();
        //Doing something that I missed to process in afterCreate()!
    }
}

Obviously, I can't call afterCreate() in the constructor of the class C, because if I create objects from class A or B, the method would not be called.

Is there a way to ALWAYS, automatically call afterCreate() when the LAST constructor ends?

Right now, thinking about the problem, maybe if I can detect that the constructor is called in a super class, I could detect whether I can call the method.

Class A {
    public A() {
        //Do something
        if(thisIsNotCalledAsASuperClass()) afterCreate();
    }
}

Class B extends A {
    public B() {
        super();
        //Do something
        if(thisIsNotCalledAsASuperClass()) afterCreate();
    }
}

Class C extends B {
    public C() {
        super();
        //Do something
        if(thisIsNotCalledAsASuperClass()) afterCreate();
    }
}

//Class D extends C {
//etc.

I don't know.... What do you think?

J0e3gan
  • 8,740
  • 10
  • 53
  • 80
Mario S
  • 1,914
  • 1
  • 19
  • 32
  • 4
    What are you trying to accomplish by doing this? It seems that `afterCreate()` as you have described it is simply a way to factor out some of what the constructor should do itself. – J0e3gan Nov 02 '14 at 22:55
  • 1
    It is probably not a very good idea: http://stackoverflow.com/a/7223444/829571 – assylias Nov 02 '14 at 22:57
  • 2
    Calling an overridable method from a constructor is very bad practice and will lead to bizarre behavior. The superclass shouldn't bother about the state of its subclasses. Only about its own state. In your example, `x` is private, so subclasses can't access it. If `x`, which is a private field of A, must be initialized by subclasses of A, then x should be an argument of the constructor of A. – JB Nizet Nov 02 '14 at 22:58
  • 1
    @J0e3gan Well, afterCreate() will be something like an "abstract" method. I'm trying to put some order using it, but I think that you're right... – Mario S Nov 02 '14 at 23:04
  • @JBNizet Fixed. The property `x` is protected, but you have reason too. As I commented the answer from Peter, I will thinking again the design. Thanks! – Mario S Nov 02 '14 at 23:11
  • Possible duplicate of [Running a method after the constructor of any derived class](http://stackoverflow.com/questions/2906958/running-a-method-after-the-constructor-of-any-derived-class) – Nathan Oct 24 '16 at 19:07

1 Answers1

6

This is a bad idea. It is generally considered an anti-pattern for a constructor to call a method which changes behaviour based on a sub-class.

If you really need this functionality, I suggest using a factory method on each class and preventing direct access to the constructors. The problem is you are calling an overridable method for an instance which is not fully initialised.

Class A {
    private A() {
        //Do something
    }
    public static A newA() {
        A a = new A();
        a.afterCreate();
        return a;
    }
}

Class B extends A {
    private B() {
        super();
    }
    public static B newB() {
        B b = new B();
        b.afterCreate();
        return b;
    }
}

Class C extends B {
    private C() {
        super();
        //Do something
    }
    public static C newC() {
        C c = new C();
        c.afterCreate();
        return c;
    }
}
J0e3gan
  • 8,740
  • 10
  • 53
  • 80
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 3
    Oh, that's a solution but I will follow your advice and I will not to try to do something like that. I will review the design again to be really sure that I will need to do it in that way. Thank you! – Mario S Nov 02 '14 at 23:08