【问题标题】:How can a child interface reuse its parents' implementations?子接口如何重用其父接口的实现?
【发布时间】:2015-05-12 03:09:27
【问题描述】:

最近我有一个面试,我被问到以下问题。给定以下类/接口结构:

问题:

如何实现接口EmployedStudent 以重用来自StudentImpl 和EmployeeImpl 的代码。

我建议将 Employee 和 Student 组合到我的实现中。

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

【问题讨论】:

  • 就代码重用而言,组合对我来说也是最好的方式。如果没有多重继承,我不知道您将如何以任何其他方式重用 both StudentImpl 和 EmployeeImpl 的代码。
  • 我也说过作曲。我想,您可以从其中一种实现中派生EmployedStudent,然后只需要对另一种实现使用组合。但我不会说这真的比直接组合更好,除非其中一个界面比另一个界面更“主要”(例如,主要方面是它是一名员工,而学生位相当次要)。

标签: java inheritance interface implementation composition


【解决方案1】:

创建一个实现Employee 和Student 的类。在您的班级中,创建EmployeeImpl 和StudentImpl 的实例。然后让您的类将所有方法调用委托给任一对象。

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

}

【讨论】:

  • 那是使用接口,我理解这个问题更像是在员工和学生类中使用实际存在的代码,而不仅仅是接口。
  • @meister_reineke:通过委托,您实际上将使用EmployeeImpl 和StudentImpl 类的现有代码。
【解决方案2】:

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

现在类 name 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
}

这是一个能力查询。它通常可以通过使用 Swimming、Flying、Driving 功能来替换繁琐的继承层次结构,例如 Vehicle、RoadVehicle、SwimmingVehicle(船)、FlyingVehicle(飞机)、WaterAirplane(?)、AmphibianTank(?)。

不同的是整个解耦。

【讨论】:

  • 这是一个超酷的解决方法!我不确定我是否会选择这样的过度组合,但它肯定表明你可以模拟这个功能。
  • 我没有把你的想法当作方法。 Person 类是什么?
  • 旨在通过展示另一种方法来表明答案可能提供多于两行。但一定要提到那个:“在类似的用例中,一个也可能......”,扩展答案。
【解决方案3】:

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

  • 每个需要的超类都有一个字段
  • 或从一个超类派生并为另一个超类提供一个字段。

然后,这些字段由“我们的”相应方法的实现来引用。

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      虽然接口隔离原则有时会有所帮助,而且有些人对接口的想法嗤之以鼻,因为接口并不保证所有实现都支持所有成员,但我建议使用 Student 和 @ 可能会有所帮助987654322@接口,其中包括isStudent和isEmployee成员,然后有Person实现这两个接口;像giveRaise() 这样的一些方法不应该对不是员工的人起作用,但是像getOutstandingPay() 这样的其他方法应该可以正常工作(如果有人没有赚到任何钱,该方法应该简单地返回零)。

      虽然将所有Person 对象使用不适用于其中许多对象的方法复杂化可能看起来很难看,但这样的设计避免了学生被录用或员工开始上课时遇到的困难。为Student、Employee 和StudentEmployee 提供单独的类,即使可以轻松做到这一点,也需要将找到工作的Student 替换为新对象实例为了成为StudentEmployee。相比之下,如果有一个 Person 类,其实例可能会或可能无法处理像 giveRaise 这样的方法,那么我们可以处理对象在其生命周期内的能力发生变化的情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-30
        • 2020-07-29
        • 2021-09-14
        • 2016-06-20
        • 2017-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多