I can't find a solution to this inheritance problem. I'm working on a program which will store information about celestial bodies. I have an abstract superclass, Body
, from which all other celestial bodies should inherit. Now, I want some bodies to have implementation by default for storing information about orbiting bodies; some bodies should be Orbitable
and some should be Orbital
. e.g. a Star is orbitable
only, a Planets and Moons are both orbitable
and orbital
, and an Asteroid is orbital
only.
public abstract class Orbital {
Body host;
protected double avgOrbitalRadius;
protected double orbitalPeriod;
public double getOrbitalRadius(){return this.avgOrbitalRadius;}
public double getOrbitalPeriod(){return this.orbitalPeriod;}
}
public abstract class Orbitable {
List<Body> satellites = new ArrayList<>();
public void addSatellite(Body sat){
satellites.add(sat);
}
public boolean hasSatellite(Body sat){
for(Body body : satellites){
if(sat.equals(body)) return true;
}
return false;
}
public boolean hasSatellite(String satName){
for(Body body : satellites){
if(satName.equals(body.getName())) return true;
}
return false;
}
public Body getSatellite(String satName){
for(Body body : satellites){
if(satName.equals(body.getName())) return body;
}
return null;
}
}
I need to have objects be able to inherit one, both, or neither of the above implementations (plus the Body
superclass which describes the foundation for any celestial body).
I've tried using interfaces with default methods but the key problem is that the implementation involves reading or modifying the object's state, which cannot be implemented with interfaces because all variables in an interface are implicitly static.
I've also viewed this and this post about very similar issues, but the inheritance of state is causing me grief.
So, how can I solve this multiple inheritance problem? Is it even possible in Java? Are there other designs that could circumvent this problem? Thanks.
Delegation can be an alternative to inheritance. Delegation means that you use an object of another class as an instance variable, and forward messages to the instance.
Consider a case where class B extends class A and Class C and both class A and C have the same method display(). Now java compiler cannot decide, which display method it should inherit. To prevent such situation, multiple inheritances is not allowed in java.
Second, in C++, it makes sense to inherit virtually from abstract interfaces, (even with the additional cost/indirection). If you don't, and the interface inheritance appears multiple times in your hierarchy, then you'll have ambiguities.
Orbitable
and Orbital
, that define (but obviously do not implement) methods for the state manipulations you want to have.Create three (abstract) classes
OrbitableBody extends Body implements Orbitable
OrbitalBody extends Body implements Orbital
OrbitableOrbitalBody extends Body implements Orbitable, Orbital
And make those three classes realize the methods from the interfaces.
Body
, OrbitableBody
, OribtalBody
or OrbitableOrbitalBody
. They will then all be a Body, implement the correct interfaces, and inherit default implementations for the interface-defined methods.
Let me approach this classic object oriented pattern problem with some visual help.
I would have two interfaces namely:
Orbitable
Orbital
Then a base class Body
. You can make it concrete or abstract depending on your implementation details. For example you can add behaviors like does it have an atmosphere? in the form of method hasAtmosphere()
. This can be abstract
first and then have your implementing classes override this.
Then I will have two additional sub-classes extending Body
and implementing each interface (remember interface separates responsibility by providing contracts for behaviors)
BaseOrbitable
BaseOrbital
BaseOrbitalOrbitable
Finally some concrete (sub-classes) implementation examples:
public class Earth extends Planet {
}
or
public class Ceres extends Asteroid {
}
or
public class Sirius extends BaseOrbitable {
}
Johannes H. answer is relatively simple and might be a good solution. It has a problem of code duplication though. Instead I suggest to think of Orbital
and Orbitable
as something your celestial bodies have and use composition and delegation:
class Body {
}
interface Orbital {
public double getOrbitalRadius();
}
interface Orbitable {
public void addSatellite(Body sat);
}
// Default common implementation, shouldn't be abstract
class OrbitalImpl implements Orbital {
protected double avgOrbitalRadius;
public double getOrbitalRadius(){return this.avgOrbitalRadius;}
// ...
}
class OrbitableImpl implements Orbitable {
List<Body> satellites = new ArrayList<>();
public void addSatellite(Body sat){satellites.add(sat);}
//...
}
class OrbitableOrbitalBody extends Body implements Orbitable, Orbital {
Orbitable orbitable;
Orbital orbital;
public OrbitableOrbitalBody() {
orbitable = new OrbitableImpl();
orbital = new OrbitalImpl();
}
public OrbitableOrbitalBody(Orbitable orbitable, Orbital orbital) {
this.orbitable = orbitable;
this.orbital = orbital;
}
@Override
public double getOrbitalRadius() {
return orbital.getOrbitalRadius();
}
@Override
public void addSatellite(Body sat) {
orbitable.addSatellite(sat);
}
}
class OrbitableBody extends Body implements Orbitable {
Orbitable orbitable;
// Use default implementation
public OrbitableBody() {
orbitable = new OrbitableImpl();
}
// If needed use orbitable that behaves differently
public OrbitableBody(Orbitable orbitable) {
this.orbitable = orbitable;
}
// delegate to orbitable
@Override
public void addSatellite(Body sat) {
orbitable.addSatellite(sat);
}
}
// Same as Orbitable
//class OrbitalBody extends Body implements Orbital {
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With