Reputation: 99
I am wondering how to convert overlapping type of inheritance to Java. I got abstract class Person, and 2 extending subclasses: Driver and Passenger. As you know, driver may also be a passenger. So the question is: what's the best way to implement overlapping in Java? I heard that the best way is to use the composition, but i don't know how to.
Upvotes: 1
Views: 1186
Reputation: 59496
This is an extension of the answer provided by dasblinkenlight.
The solution is based on the component pattern described here by the Team Leader of the Tony Hawk dev team back in the '90s and it's often used in game development.
Disclaimer: I'm going to write the code without a Java compiler so please do tell me whether there are syntax errors.
abstract class Person {
public String name;
}
interface DriverInterface {
public void drive();
}
interface PassengerInterface {
public void seat();
}
class DriverComponent {
private Person person;
public DriverComponent(Person person) {
self.person = person;
}
public void drive() {
System.out.println("I'm" + person.name + " and I'm driving");
}
}
class PassengerComponent {
private Person person;
public PassengerComponent(Person person) {
self.person = person;
}
public void drive() {
System.out.println("My name is " + person.name + " and I'm passenger");
}
}
class Driver extends Person implements DriverInterface, PassengerInterface {
private DriverComponent driverComponent;
private PassengerComponent driverComponent;
private String name;
public Person(String name) {
driverComponent = DriverComponent(this);
passengerComponent = PassengerComponent(this);
}
public void drive() {
driverComponent.drive();
}
public void seat() {
passengerComponent.seat();
}
}
class Passenger extends Person implements Passenger {
private DriverComponent driverComponent;
private PassengerComponent driverComponent;
public String name;
public Passenger(String name) {
driverComponent = DriverComponent(this);
passengerComponent = PassengerComponent(this);
}
public void seat() {
passengerComponent.seat();
}
}
I really hope there are not syntax errors.
The power of this approach is that we do not replicate the logic of a Driver
or of a Passenger
because we write this code only once inside the related component.
The Component approach also allow us to easily create (and maintain) even combination of entity (like Driver, Passenger) and behaviour (DriverInterface
, PassengerInterface
) simply combining the related component.
It's the best alternative to multiple inheritance not supported by Java and it way better and clearer.
Upvotes: 1
Reputation: 503
Similar to dasblinkenlight's answer, but I think more technically correct:
interface Person{}
interface Pet{}
interface HumanPassenger extends Person{}
interface PetPassenger extends Pet{}
interface Driver extends HumanPassenger{}
In this case Driver extends HumanPassenger and Person through HumanPassenger's ancestors. You can also do this explicitly via:
interface Driver extends HumanPassenger, Person{}
The reason that I say this is more technically correct is through the "is-a" relationship that descendant classes should have. For example, a HumanPassenger is a Person, a Person is not a HumanPassenger (a person could be anything that a person could be, not just a human passenger) in dasblinkenlight's answer, a person is a passenger, but what if a person is a pedestrian...
EDIT: Human Passenger, PetPassenger, and Driver, could all also be classes, I was just keeping it simple. example of Driver class:
class Driver extends HumanPassenger implements Person{}
or if HumanPassenger was an interface still:
class Driver implements HumanPassenger{}
or
class Driver implements HumanPassenger, Person{}
All would achieve the same things, though only the classes would be capable of instantiation of course.
Upvotes: 0
Reputation: 726549
When a single class can play two roles in a system, an inheritance-based approach in Java is to define two interfaces, and have the class implement them:
interface Passenger {
... // Methods applicable to passengers
}
interface Driver {
... // Methods applicable to drivers
}
class Person implements Driver, Passenger {
... // A person can be a driver or a passenger
}
class Pet implements Passenger {
... // A pet can be only a passenger
}
You can use composition internally to implement the interfaces by forwarding method calls to private helper "passenger" and "driver" objects inside Person
.
In Java-8 you can place logic that is common to all implementing classes into default method implementations.
Upvotes: 4