Recently I had an interview and I was asked the following question. Given the following class/interface structure:
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.
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();
}
}
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.
As java doesn't support multiple inheritance, you could/should
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 .
With Java 8, you can move code into the interface itself. That solves the "multiple inheritance" problem.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.