1

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.

3
  • 3
    If the driver is always a passenger, why don't you make driver a subclass of passenger? Commented Jun 13, 2016 at 18:50
  • One solution dasblonkenlight approach. Other solution: Person having list of roles using composition. Commented Jun 13, 2016 at 18:58
  • related: stackoverflow.com/questions/56860/… "if it looks lika a duck, quacks like a duck, but needs battieries - you probably have the wrong abstraction" Commented Jun 13, 2016 at 19:00

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Your abstract class Person

abstract class Person {
    public String name;
}

This way we expose the behaviour of Driver

interface DriverInterface {
    public void drive();
}

And here we export the behaviour of Passenger

interface PassengerInterface {
    public void seat();
}

Here we put the actual logic of a Driver

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");
    }
}

And here we put the logic of Passenger

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");
    }
}

Finally the Driver class

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();
    }

}

And the Passenger class

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();
    }
}

Wrap up

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.