子接口如何重用其父项的实现?

时间:2015-03-10 15:34:12

标签: java inheritance interface implementation composition

最近我接受了一次采访,我被问到以下问题。给定以下类/接口结构:

enter image description here

问题:

如何实现接口EmployedStudent以重用StudentImplEmployeeImpl中的代码。

我建议将员工和学生组合到我的实施中。

根据采访者的反应,我认为他们认为这不是最好的解决方案。我花了很多时间思考它,但我无法想出另一个解决方案。

5 个答案:

答案 0 :(得分:5)

创建一个实现EmployeeStudent的类。在您的课程中,创建EmployeeImplStudentImpl的实例。使您的类将所有方法调用委托给其中一个对象。

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

}

答案 1 :(得分:3)

因此,你可以让implements Employee, Student在内部委托给EmployeeImpl和StudentImpl,但也可以从一个实现类继承。

现在, 名称 类EmployedStudent(不是StudyingEmployee或BothEmployeeAndStudent)建议:

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

是的,因为只委托给另一个班级,效率会更高一些。

然而,用例远非现实:所有类型的组合都可以想到几个类。在这种情况下,您的解决方案更具普遍性真正普遍,是一种查找机制:

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
}

这是能力查找。它通常可以通过使用游泳,飞行,驾驶等功能取代繁琐的继承等级,例如Vehicle,RoadVehicle,SwimmingVehicle(船),FlyingVehicle(飞机),WaterAirplane(?),AmphibianTank(?)。

不同之处在于整个脱钩。

答案 2 :(得分:1)

由于java不支持多重继承,你可以/应该

  • 要么为每个想要的超类都有一个字段
  • 或派生自一个超类,并为另一个超类提供一个字段。

这些字段随后由&#34;我们的&#34;实施各自的方法。

这是design patterns from the GoF之一,我认为是Proxy pattern

答案 3 :(得分:1)

使用Java 8,您可以将代码移动到界面本身。这解决了“多重继承”问题。

答案 4 :(得分:1)

虽然接口隔离原则有时可能会有所帮助,但有些人嘲笑接口的概念并不承诺所有实现都支持所有成员,我建议Student可能会有所帮助和Employee接口,包括isStudentisEmployee成员,然后Person实现两个接口;像giveRaise()这样的某些方法不适用于非员工的人,但getOutstandingPay()之类的其他方法应该可以正常工作(如果有人没有赚到钱,该方法应该只返回零)

虽然使用不适用于其中许多对象的方法使所有Person对象复杂化似乎很难看,但这样的设计避免了在学生被雇用或员工开始上课的情况下的困难。为StudentEmployeeStudentEmployee设置单独的类,即使可以轻松完成,也需要将Student的工作替换为新对象实例以成为StudentEmployee。相比之下,如果有一个Person类,其实例可能或可能无法处理giveRaise之类的方法,那么可以处理对象的能力在其生命周期内发生变化的情况。