I have a two abstract classes FlyingBird and RunningBird
public abstract FlyingBird extends Bird implements IFlyingBird {}
public abstract RunningBird extends Bird implements IRunningBird {}
Now I want to have an another abstract class that is both IRunningBird and IFlyingBird
public abstract FlyingRunningBird extends Bird implements IFlyingBird, IRunningBird {}
In this class I am duplicating all the code from FlyingBird and RunningBird
Aggregation of dependent class is not possible as both classes are abstract
The issue is if any bug fix or modification that is done on either FlyingBird or RunningBird will not reflect in FlyingRunningBird. I need to update the FlyingRunningBird too.
Is there any we can avoid this code duplication in FlyingRunningBird? or
Use FlyingBird and RunningBird in FlyingRunningBird to avoid code duplication?
CodePudding user response:
Java was designed with the problems of multiple inheritance in C in mind. So only single inheritance and multiple interfaces. At that time in C there could be ambiguity of a method that could belong to two parent classes.
To achieve your goal, the solution is to use delegating:
- specify interfaces
- specify implementations
- delegate
Using an other conventional naming:
public interface Flying {
void fly();
double getWingSpan();
}
public class FlyingImplementation {
public FlyingImplementation(Bird bird)
...
}
public interface Running {
void run();
double getRunningSpeed();
}
public class RunningImplementation {
public RunningImplementation(Bird bird) {}
...
}
public abstract FlyingRunningBird implements Flying, Running, Bird {
private final Flying birdFlying;
private final Running birdRunning;
protected FlyingRunningBird() {
birdFlying = new FlyingImplementation(this);
birdRunning = new RunningImplementation(this);
}
@Override
public void fly() {
birdFlying.fly();
}
@Override
void run() {
birdRunning.run();
}
...
}
The common things in Bird, which also could have a base class. Flying and Running are capabilities, names adjectives, sole responsibility: flying resp. running.
Delegating to birdFlying and birdRunning makes the "multiple inheritance" explicit and is by no means less expressive.
CodePudding user response:
I think there are two ways you can approach this:
- Move the method implementations as
defaultmethods in the correspondinginterface, given that you're using Java 8 and those methods do not need to access fields (in which case you'll need to have some accessors in your interface or reconsider your design). - Favor composition over inheritance, though in this particular case this doesn't seem quite natural. I.e. your
FlyingRunningBirdcould be provided with an instance ofFlyingBirdand an instance ofRunningBird(at construction time), and it will simply delegate the method calls for each of the interfaces to the corresponding implementation.
CodePudding user response:
In your case, you may use Helper classes -> classes that do not fall anywhere in the hierarchy but have the common code to avoid duplicacy.
Otherwise, from the OO point of view -
- A FlyingRunningBird may not fly the same as a FlyingBird.
- A FlyingRunningBird may not fly the same as a RunningBird
