9

Recently I had an interview and I was asked the following question. Given the following class/interface structure:

enter image description here

Question:

How can one implement interface EmployedStudent to reuse code from StudentImpl and EmployeeImpl.

I suggested to compose Employee and Student into my implementation.

Based on the interviewer's reaction I don't think they found it to be the best solution. I spent a lot of time thinking about it but I cannot come up with another solution.

Necreaux
  • 9,451
  • 7
  • 26
  • 43
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • Composition sounds like the best way to me too, in terms of code reuse. Without multiple inheritance, I don't know how you would reuse code from *both* `StudentImpl` and `EmployeeImpl` any other way. – christopher Mar 10 '15 at 15:38
  • 1
    I'd've said composition as well. You *could* derive `EmployedStudent` from one of the implementations and then only need to use composition for the other one, I suppose. But I wouldn't have said that was really better than straight composition unless one of the interfaces is more "primary" than the other (e.g., that the primary facet was that it was an employee, with the student bit being fairly secondary). – T.J. Crowder Mar 10 '15 at 15:39

5 Answers5

5

Create a class that implements both Employee and Student. In your class, create an instance of both EmployeeImpl and StudentImpl. Make your class delegate all method calls to either one of the objects then.

public class EmployedStudent implements Employee, Student {

  private EmployeeImpl employee = new EmployeeImpl();
  private StudentImpl student = new StudentImpl();

  public int getSalary() {
    return this.employee.getSalary();
  }

  public float getAverageGrade() {
    return this.student.getAverageGrade();
  }

}
user1438038
  • 5,821
  • 6
  • 60
  • 94
  • 1
    thats using interfaces, i understood the question more like using actually existing CODE in the employee and student classes, not only the interfaces. – meister_reineke Mar 10 '15 at 15:47
  • 2
    @meister_reineke: Through the delegation, you actually *will* be using existing code of the ``EmployeeImpl`` and ``StudentImpl`` class. – user1438038 Mar 10 '15 at 16:00
3

So, you could have implements Employee, Student internally delegating to both EmployeeImpl and StudentImpl, but also inherit from one implementation class.

Now the class name EmployedStudent (not StudyingEmployee or BothEmployeeAndStudent) suggests:

class EmployedStudent extends StudentImpl implements Employee {
    Employee asEmployee = new EmployeeImpl();

Yeah, a tiny bit more efficient as only delegating to one other class.

The use-case is however far from realistic: all kind of combinations are thinkable of several classes. In that case your solution is more universal. Really universal, is a lookup-mechanism:

public class Person {
    public <T> T as(Class<T> klazz) { ... }
}

Person person = ...;
Student asStudent = person.as(Student.class);
if (asStudent != null) {
     ...
}
Employee asEmployee = person.as(Employee.class);
if (asEmployee != null) {
    asEmployee.quitJob();
    asEmployee = person.as(Employee.class); // null
}

That is a lookup of capabilities. It typically can replace a cumbersome inheritance hierarchy, say of Vehicle, RoadVehicle, SwimmingVehicle (boat), FlyingVehicle (air plane), WaterAirplane (?), AmphibianTank (?) by using capabilities Swimming, Flying, Driving.

The difference is the entire decoupling.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • This is a super cool workaround! I'm not sure I'd go for something like this over composition, but it definitely shows that you can *simulate* this functionality. – christopher Mar 10 '15 at 19:46
  • I didnt caught your thought about as method. what the Person class? – gstackoverflow Mar 10 '15 at 23:16
  • Intended to show that an answer might provide more than two lines, by showing another approach. But definitely mention _that_: "In similar use-cases one also may...", Extended the answer. – Joop Eggen Mar 11 '15 at 07:40
1

As java doesn't support multiple inheritance, you could/should

  • either have a field for each of the wanted superclasses
  • or derive from one superclass and have a field for the other one.

The fields are then referred to by "our" implementation of the respective methods.

This is one of the design patterns from the GoF, I think it is the Proxy pattern.

glglgl
  • 89,107
  • 13
  • 149
  • 217
1

With Java 8, you can move code into the interface itself. That solves the "multiple inheritance" problem.

Necreaux
  • 9,451
  • 7
  • 26
  • 43
1

While the Interface Segregation Principle can sometimes be helpful, and some people scoff at the idea of interfaces which don't promise that all implementations will support all members, I would suggest that it may be helpful to have Student and Employee interfaces which include isStudent and isEmployee members, and then have Person implement both interfaces; some methods like giveRaise() shouldn't work on someone who isn't an employee, but others like getOutstandingPay() should work just fine (if someone hasn't earned any money, the method should simply return zero).

While it may seem ugly to complicate all Person objects with methods that won't be applicable for many of them, such a design avoids difficulties in the event that a student gets hired, or an employee starts taking classes. Having separate classes for Student, Employee, and StudentEmployee, even if one could do so easily, would require that a Student who got a job be replaced with a new object instance in order to become a StudentEmployee. By contrast, if one has a Person class whose instances may or may not be able to handle methods like giveRaise, then one can handle situations where objects' abilities change during their lifetimes.

supercat
  • 77,689
  • 9
  • 166
  • 211