Is there a way optional inheritance as described in the following case?
Say start with this:
Note: there are can be more than 4 child classes.
Now there is an optional capability called "Autonomous Transport" as here.
Option 1: As in this picture above I can have all child classes inherit from "Autonomous Transport" but I don't want that. Say, there cannot be an autonomous Train.
Option 2: Not have "Autonomous Transport" strictly in between but have individual classes inherit (may be with interface) like "Car", "Autonomous Car", "Truck", "Autonomous Truck" as needed. But not an attractive option as there are way more than 4 child classes
Option 3: Possibly, I can use dependency injection and inject "Autonomous" capability where needed but I cannot add any framework like dagger etc.
Are there any other ways, it can be done cleanly with Java? Basically, if "Train" cannot be autonomous, I do not want any related business logic there.
To keep it simple:
Option 1
abstract class Transport {
foo();
}
abstract class AutomonousTransport extends Transport {
bar();
}
class Car extends AutonomousTransport {
// inherits foo and bar
}
class Train extends Transport {
//inherits only foo(), which is ok, since Train is still a transport
}
With this approach you'll have to decide from which class to inherit so that you'll get the desired capabilities.
The potential drawback of this method is if you have many different capabilities like this (and in java you can extend only from one class).
To overcome this issue, if you only inherit the capability (behavior) and not the state, consider using interfaces with default methods instead of abstract classes. This works somewhat like Traits in other languages with some restrictions:
interface Transport {
default foo () {...}
}
interface AutonomousTransport extends Transport {
default bar() {}
}
interface WheelSupportTransport extends Transport {
default rotateWheelLeft() {...}
default rotateWheelRight() {...}
}
class Car implements AutomonousTransport, WheelSupportTransport {
}
class Train implements Transport {...}
Option 2
abstract class Transport {
foo()
}
final class AutonomousStuff { // final to prohibit inheritance from it
bar()
}
class Car extends Transport {
AutonomousStuff autonomousStuff;
}
class Train extends Transport {
// only foo
}
This approach is based on "prefere composition over inheritance" idea. You add the behavior to the required class as an internal data field and gain the access to the required set of methods (capabilities) through this field.
Option 3
abstract class Transport {
foo()
}
abstract class AutonomousCapable extends Transport {
private final Transport transport;
public AutonomouseCapable(Transport transport) {
this.transport = transport;
}
bar()
foo() {
transport.foo();
}
}
class Car extends Transport {}
class Train extends Transport {}
When creating the car, use new AutonomousCapable(new Car())
This follows the idea of "decorator" (a.k.a. wrapper) pattern. You "decorate" the object (car) with additional set of behaviors in runtime.
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