10

I have a People class, and Student and Employee classes which inherit from it. But if I have a person who is both a Student and an Employee...

... How would you go about implementing this?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Sihan Wang
  • 197
  • 1
  • 2
  • 13
  • I wouldn't make them classes. So what's the actual problem? – Ordous Jan 26 '15 at 17:42
  • @Ordous why not make classes? – Sihan Wang Jan 26 '15 at 17:43
  • @SihanWang What **exactly** is the problem? What functionality do `Student` and `Employee` need to have? – Mureinik Jan 26 '15 at 17:44
  • It feels like a bad design, can you explain what you want to do? – Marco Acierno Jan 26 '15 at 17:45
  • @Mureinik it is a interview question, i think you can make any assumption here. – Sihan Wang Jan 26 '15 at 17:45
  • @MarcoAcierno it is a interview question, i think you can make any assumption here – Sihan Wang Jan 26 '15 at 17:46
  • 1
    Since Java does not support multiple inheritances you basically have three options - a) rethink the design having business concepts in class layout is not always a good fit. b) use interfaces, you can implement multiple. c) use composition (having a personInfo and a studentInfo field) – eckes Jan 26 '15 at 19:32
  • possible duplicate of [Java Multiple Inheritance](http://stackoverflow.com/questions/21824402/java-multiple-inheritance) – Raedwald Jan 27 '15 at 07:55

5 Answers5

18

That's a classic example of an improperly analyzed problem domain. Yes, in some situations, it may be proper to think of "Student" as a type of "Person" and an "Employee" as a type of "Person", but - depending on your problem domain - it may also not be appropriate.

If your domain requires that something be both a "Student" and an "Employee", you should consider if the relation between "Student" and "Person" in your problem domain is really an "is-a" relationship.

It could be that in this particular case, being a student is merely an attribute of a particular person. So, John Doe is a person, who may also have a "current occupation" of "Student". In this case, he may have a list of several "current occupations". And the relationship in such a world becomes "has-a" rather than "is-a". So "Student" and "Employee" become subclasses of "Occupation".

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
  • 1
    I get the point, but I did not get how to solve this problem. Thank you – Sihan Wang Jan 26 '15 at 17:53
  • It's a bit hard to give you a concrete example, without knowing what you were asked to implement in your interview. Perhaps you should add the full interview question text to your original question. – RealSkeptic Jan 26 '15 at 17:57
17

As per the comment:

it is a interview question, i think you can make any assumption here

If this is the case, the only correct answer is to describe your assumptions, and how you address them.

If you strictly adhere to the requirements, you could make Student and Employee interfaces and have different classes implement them:

public interface Student {
    void learn();
}

public interface Employee {
    void work();
}

public class Person {
    // properties, getters and setters for name, age, sex, etc.
}

public class StudentPerson extends Person implements Student {
    @Override
    public void learn() {}
}

public class EmployeePerson extends Person implements Employee {
    @Override
    public void work() {}
}
public class StudentEmployeePerson extends Person implements Student, Employee {
    @Override
    public void work();

    @Override
    public void learn() {}
}

Taking this an extra mile would be to extract the logic of work() and learn() to helper classes, and have StudentPerson, EmployeePerson and StudentEmployeePerson call them respectively.

But this, IMHO, missed the point of the exercise.

A student who also has a job is still a student. He cannot be a separate class from a student who doesn't.

I'd create a Role interface, have Student and Employee implement it, and allow a Person to have multiple Roles, so he can be both a student and an employee:

public interface Role {
    void perform();
}

public class Student implements Role {
    @Override
    void perform() { /* go study */ }
}

public class Employee implements Role {
    @Override
    void perform() { /* go work */ }
}

public class Person {
    // properties, getters and setters for name, age, sex, etc.

    private Set<Role> roles = /* initialized somehow */

    public void doStuff() {
        for (Role role : roles) {
            role.perform();
        }
    }
}

EDIT:
To answer the question in the comment, a person who is both a student and an employee would be constructed by adding Roles. For simplicity's sake the snippet below assumes that these classes have constructors from the relevant properties, and that Person has methods to add and remove the Roles to the internal set:

Person person = new Person("John Doe", 21, Sex.Male);
person.addRole(new Student("Stack Overflow University"));
person.addRole(new Employee("Secret Government Spy"));
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • That is the first time I see the second solution. In this case, how could instantiate for one person who are student and employee? Thank you – Sihan Wang Jan 26 '15 at 18:10
  • @SihanWang I've edited my answer with an example of how this can be done. – Mureinik Jan 26 '15 at 21:15
  • if we want to have a student, would we use function addRole of Person, or just use Student class? – Sihan Wang Jan 26 '15 at 21:25
  • @SihanWang In the second implementation - you'd have a `Person`, with a single `Student` role. If this is a common usecase, it might be worth adding a constructor with a `Set` or even `Role` parameter as syntactic sugar: `new Person ("John Doe", 21, Sex.Male, Collections.singleton(new Student("NYU")))` or even `new Person ("John Doe", 21, Sex.Male, new Student("NYU"))` – Mureinik Jan 26 '15 at 21:28
  • 1
    This is very beautiful design. – Sihan Wang Jan 26 '15 at 21:44
  • I am new to java, is there disadvantage for the second solution comparing with the first one? – Sihan Wang Jan 26 '15 at 21:48
  • @SihanWang the main problem, IMHO, is that you don't have a good way to restrict the types of people you can pass to method. E.g., it'll be quite clumsy to create a `Classroom` class which holds a list of students, whereas in the first solution, you could just have `Classroom(List)`. In the end, in all boils down to what the requirements are. – Mureinik Jan 26 '15 at 21:52
4

Since Java doesn't allow multiple inheritance you should define interfaces for Student and Employee instead of inheriting from them as base classes.

bpmason1
  • 1,900
  • 1
  • 12
  • 9
4

What you could do is, you can change the public class Employee to public interface Employee and then you can do public class Student extends People implements Employee

You will have to work like this because in java, one class can inherit only from one class at the most. Cheers.

nom
  • 256
  • 3
  • 16
1

In Java it is only possible to extend one superclass. However, Java offers interfaces and one class can extend more than one interface.

You could organize your class structure like this:

interface People
interface Student extends People
interface Employee extends People

Then your employing students could be:

class EmployingStudent implements Student, Employee

In case People is a class that cannot be changed you can do:

interface Student
interface Employee
class EmployingStudent implements Student, Employee

So the only difference would be that Student and Employee wouldn't extend People then.

MinecraftShamrock
  • 3,504
  • 2
  • 25
  • 44