tags:

views:

384

answers:

8

The problem is this: I have an abstract class that does some work in its constructor, and a set of child classes that implement the abstract class:

class AbstractClass {
     AbstractClass(){ /* useful implementation */ }
}

class ConcreteClass1 extends AbstractClass {
     ConcreteClass1(){ super(); /* useful implementation */ }
}

Then, the concrete classes need to be customized and one solution is to extend the concrete classes:

class CustomizedClass1 extends ConcreteClass1 {
    CustomizedCLass1(){ super(); /* useful implementation */ }
}

BUT the problem is that the customized classes need only to call the abstract class's constructor and not the concrete class's constructor.

How do you achieve this? Suggestions to change the class's relationships are valid.

EDIT: The concrete example is that ConcreteClass1 and CustomizedClass1 have different sets of data (ConcreteData1 and CustomizedData1), and it is retrieved from the database in the class's constructor. The problem is that creating an instance of CustomizedClass1 will retrieve both data entities.

I am aware that using simple inheritance it's probably not the best thing to do, that's why I pointed out that suggestions to change the class's relationships are valid.

+19  A: 

You cannot do this in Java. I frequently have students who want to do this, but I have never seen a case where it is really what they wanted to do.

Can you give a concrete example of what it is you want to do and why (your description is too vague) and I am sure a solution can be achieved :-)

Edit:

For a real world example of why you do not want to do this (normally) would be a hierarchy like:

Animal (constructor makes the eyes)
  |
Mammal (constructor makes the lungs)
  |
Human (constructor sets the language)

If the Human constructor could skip over the Mammal constructor then you would wind up with a Human who has no lungs... not very useful.

TofuBeer
Animal<-Mammal<-Aquaman: Inherits everything but the lung construction in Mammal, and implements its own gills. ;)
erickson
Then the constructor from Mammal should take a "breathing mechanism" as an argument to the constructor and assign that to the instance variables that used to be lungs :-)
TofuBeer
I think the point this is missing is that the Mammal constructor is not necessarily idempotent and you don't always want to invoke the same constructor from a subclass. You still must invoke at least one constructor, but not everyone needs the same constructor.
MattMcKnight
I'd say if you have constructors initializing the class in wildly different ways then you are probably doing something "wrong".
TofuBeer
If Aquaman has gills instead of lungs, then he's an Amphibian, not a Mammal. Anyway - the characteristic that uniquely identifies a Mammal is mammary glands - reptiles have lungs too!
belugabob
Yeah I made my students look that one up this year (the mammary glands) - but lungs seem more important :-) SOme fish also have lungs so Aquaman may have both. Regardless you still cannot skip a constructor and would probably never have a legitimate reason to, super heroes aside.
TofuBeer
+8  A: 

Any instance of CustomizedClass1 is also an instance of ConcreteClass1, by definition, so it must be constructed as a valid ConcreteClass1 instance before the CustomizedClass1 constructor can run. Otherwise, what would happen if you called ConcreteClass1 methods on it? They'd be trying to operate on variables that haven't been initialized yet.

If you think you need to do this, chances are your design needs re-thinking. If you only want some of the functionality from ConcreteClass1, for example, that functionality could be factored out into a superclass of ConcreteClass1, and CustomizedClass1 could extend that to get just the functionality that it needs.

Please provide more information about the relationship between these classes.

Wyzard
+1  A: 

This sounds to me like a mixture of concerns - something Java is not well equipped to handle.

While it is not the answer you were hoping for or one that I am proud to type, you could simply create ConcreteClass2 that mimics ConcreteClass1 and uses the AbstractClass's constructor.

As @TofuBeer said, this is not something that Java supports. This is why some modern languages (i.e. Scala w/ Traits) are gaining passionate developers.

rynmrtn
A: 

Why not just actually customize a newly-created ConcreteClass1 instance to behave like an AbstractClass instance (provided that ConcreteClass1 has corresponding protected methods just for that)? I.e.:

class AbstractClass {
     public AbstractClass() { /* useful implementation */ }
}

class ConcreteClass1 extends AbstractClass {
     public ConcreteClass1() { 
        /* A hidden super() call put here by the compiler. */
        /* Useful implementation */ 
     }

     protected void customize_with(SomeParams customization_params) {
        /* 
        Customize this ConcreteClass1 instance according to parameters 
        passed. As a result, the instance behavior will 'revert' (in the 
        way you need it) to that of an AbstractClass instance.
        */
     }
}

class CustomizedClass1 extends ConcreteClass1 {
    public CustomizedCLass1() {
        /* A hidden super() call put here by the compiler. */
        customize_with(customization_params);
        /* Rest of useful implementation */ 
     }
}

The design intentions and logic here may be as follows:

  1. You want to get the (basic) behavior of ConcreteClass1 via inheritance, you inherit from it (this of course imposes designing it worth inheriting from).

  2. You would like to customize the behavior provided by ConcreteClass1 by default. The customization you would like to achieve can usually be described with some parameters. Just pass these parameters to a special method of the CustomizedClass1 (which can be protected), and name it customize() accordingly.

  3. The customization performed in the ConcreteClass1() constructor can be any, specifically, the class instance behavior can be 'reverted' to that of AbstractClass, which you are probably asking for (if I get it right).

  4. Calling customize_with() may actually introduce some overhead depending on the actual stuff done in ConcreteClass1(), in this case using overloaded (and possibly protected) constructors is definitely a better solution, unless you would like ConcreteClass1' instances to be dynamically customizable (in which case customize_with() and probably the rest of ConcreteClass1 should be designed accordingly i.e. supporting such behavior by contract).

Excuse me if anything's wrong with the syntax (I have not written much Java code).

mlvljr
+6  A: 

Easy (but why?):

class AbstractClass {
   AbstractClass(){ /* useful implementation */ }
}

class ConcreteClass1 extends AbstractClass {
     ConcreteClass1(){ super(); /* useful implementation */ }
     ConcreteClass1(boolean skip){ super(); }
}
class CustomizedClass1 extends ConcreteClass1 {
     CustomizedCLass1(){ super(true); /* useful implementation */ }
}
MattMcKnight
never thought of that... but I also ask the "but why?" question too :-)
TofuBeer
My charitable guess is in ConcreteClass1 he could be doing some initialization of external resources, and in CustomizedClass1 he wants different external resources initialized.
MattMcKnight
if this were the case then he probably needs to create a class that is a sibling of the parent, or refactor ConcreteClass1 into two different classes.
Ken Liu
@KenLiu Simply because it has different initialization process you would recommend creating another class that has no behavior? I can think of lots of cases where this is the desired behavior.
MattMcKnight
+7  A: 

Two comments: Firstly, you're not supposed to think in terms of 'jumping over' constructors like this. Secondly, it really sounds like you need to rethink your class relationships.

Any time you find yourself thinking "A extends B, except that..." is a very good time to look at things further. 'Extends' implies 'is a', which is an either/or relationship: having optional behaviour adds grey areas which will bite you later on.

As people have said, you could provide multiple constructors on ConcreteClass1 to do the initialization you require in each case, maybe making them protected so that they can only be used by subclasses. But here's a question: what if someone wants to write CustomizedClass2 that needs some (but not all) of the functionality in ConcreteClass1? Do you add another custom constructor?

julian_t
All we're talking about here is skipping whatever initialization in being done in the constructor, not "some (but not all) of the functionality". That would be a LSP violation. :-)
MattMcKnight
In your example it may be a better to design (and view) ConcreteClass1 as a 'swiss-knife' customizable class (which can be both inherited and instantiated on its own) beforehand. So yes, if you really forgot about the needed functionality (or the requirements have changed) and definitely need to use exactly the ConcreteClass1 class as a basis for CustomizedClass2 -- add appropriate methods (incl. constructors) or customize the existing ones. That could be a rationale behind the topic starter's design.
mlvljr
+1  A: 

One way I came up with:

class AbstractClass {
     AbstractClass(){ init(); }
     protected init(){ /* useful implementation */ }
}

class ConcreteClass1 extends AbstractClass {
     ConcreteClass1(){ init(); /* useful implementation */ }
}

class CustomizedClass1 extends ConcreteClass1 {
    CustomizedCLass1(){ init(); /* useful implementation */ }
}

In this way, CustomizedClass1 gets the behavior it needs from AbstractClass without passing through ConcreteClass1 initializations.

EDIT: Ouch, this doesn't work because the parent's constructors are implicitly called as one of the commenters pointed out, I think the easy way is to have different constructors.

German
This works. I think a lot of the answers on here are crazy. I think you could use the way I suggested as well, by having multiple constructors. There are often times where you want to create an object without running the default initialization. I don't understand why the highest rated poster thinks it is some kind of crime.
MattMcKnight
Could you please name the *crazy* ones? :)))
mlvljr
@mlvjr Yours isn't crazy...it's actually pretty close to this answer. The crazy ones are the ones that take this guy to woodshed for not asking his question clearly so they can demonstrate their "strong" Object Oriented understanding.
MattMcKnight
It just came to me, German, that you are wrong in his example - ConcreteClass1 initializations will not be passed, have just tested it to be sure, the source file is at <languageblah.googlecode.com/files/Main.java>
mlvljr
Thats because the language enforces always calling the parent's constructor and in your case this call is sort of implicit and auto-generated (because the parent's constructor has no args i.e. is the default one).
mlvljr
A: 

Is CustomizedData1 a subclass of ConcreteData1? If so, then I would suggest having a (possibly protected) constructor for ConcreteClass1 that takes in a ConcreteData1 to use instead of fetching its own during initialization. This way, CustomizedClass1 can fetch its CustomizedData1 and pass it to its call to super. Unfortunately this may be tricky or fairly impossible if you can't fetch the data prior to some internal init.


class ConcreteClass1 extends AbstractClass {
     ConcreteClass1(){
          this(...fetch data as before...);
     }
     ConcreteClass1(ConcreteData1 data){
          myData = data;
          ...
     }
}
class CustomizedClass1 extends ConcreteClass1 {
     CustomizedCLass1(){
          super(new CustomizedData1(...));
          ... 
     }
}

But then CustomizedClass1 probably needs a reference to the data as a CustomizedData1 not merely a ConcreteData1. It could just typecast its inherited ConcreteData1 all the time, but that seems yucky. But if it stores its own reference to the data, then there is a need to keep the references in sync if they're not final.