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开发者_如何学Go 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.
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.
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 */ }
}
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.
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?
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.
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.
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:
You want to get the (basic) behavior of
ConcreteClass1
via inheritance, you inherit from it (this of course imposes designing it worth inheriting from).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 theCustomizedClass1
(which can be protected), and name itcustomize()
accordingly.The customization performed in the
ConcreteClass1()
constructor can be any, specifically, the class instance behavior can be 'reverted' to that ofAbstractClass
, which you are probably asking for (if I get it right).Calling
customize_with()
may actually introduce some overhead depending on the actual stuff done inConcreteClass1()
, in this case using overloaded (and possibly protected) constructors is definitely a better solution, unless you would likeConcreteClass1
' instances to be dynamically customizable (in which casecustomize_with()
and probably the rest ofConcreteClass1
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).
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.
Yes you can tweak! Add another method to parent class(B) and in your Child class(C) call it as super.executeParentA(); in this method call super.execute()
A --> execute()
B --> executeParent_A() { super.execute(); }
C --> super.executeParent_A();
-Mehboob
I can think of two cases where one might want to do this (actually not):
Case 1, ConcreteClass2 runs shared initialisation from the top class, but then does its own initialisation sequence, which is different/conflicts than the one in ConcreteClass1 -> have an init () method and override it (instead of attempting to override the ConcreteClass1's constructor).
Case 2, you have polymorphic initialisation of one (or more) class member (this is actually a specific case of the previous one):
public class ConcreteClass1 extend AbstractClass
{
protected F1 f;
public ConcreteClass1 () {
super ();
this.f = new F1();
}
}
public ConcreteClass2 extends ConcreteClass1
{
public ConcreteClass2 () {
super (); // I'd like to do super.super() instead (no, you don't)
this.f = new F2(); // We wasted time with new F1 ();
}
}
In such case, either use the init() approach, or do this:
protected ConcreteClass1 ( F1 f ) {
super ();
this.f = f;
}
public ConcreteClass1 () {
this ( new F1 () );
}
...
public ConcreteClass2 () {
super ( new F2 () );
}
In other words, make the reason for the jump explicit, for implicitly jumping over the hierarchy is forbidden and for the good reasons explained in other answers.
精彩评论