我们怎样才能摆脱不必要的继承?

时间:2010-06-22 08:52:28

标签: java oop

我在完成的采访中有一个问题,我不会得到正确的答案。

假设我们有3个类,Base,Derivate1和Derivate 2, 他们的关系如下所示

public class Base {...}

public class Derivate1 extends Base {...}

public class Derivate2 extends Derivate1 {...}

然后我们发现Derivate1和Derivate2对我们的程序来说是不必要的,但它们的方法实现很有用。那么,我们如何摆脱Derivate1和Derivate2但仍然保留他们的方法呢?在这种情况下,我们期望用户无法创建Derivate1和Derivate2的新实例,但他们仍然可以使用Derivate1和Derivate2中的方法实现。当然,我们允许更改Base类中的代码。

你怎么看待它,你能告诉他们实际上在问什么吗?

非常感谢。

PS。

当我对他们进行讨论时,我的面试官会有一些提示。

  • 派生类来自第三方。它们的设计很糟糕,所以我们不希望我们的客户端使用它们,这意味着用户不应该允许从派生类创建实例。

  • derviate类包含对Base类有用的重写方法,我们可以在Base中创建具有不同名称的方法,以在派生类中实现那些有用的行为。

感谢所有有趣的答案......

8 个答案:

答案 0 :(得分:2)

简单的重构:

  1. 将所有代码从Derivate1Derivate2复制到Base
  2. 删除Derivate1Derivate2
  3. 确保没有遗漏的引用(如果您已经将Derivate个对象的指针作为Base,那么您应该是好的)
  4. 编译
  5. ?????
  6. 利润!

  7. 即使您在层次结构中有更多子类,例如Derivate3Derivate4,也不应该让它们扩展Base

答案 1 :(得分:2)

(非静态)来自Derivate1Derivate2的方法仅在我们创建Derivate1Derivate2个实例时才可用。创建Base实例(与new Base()一样)将不允许访问在子类中声明的(非静态)方法。

因此,为了保留这些方法,可以将它们添加(重构)到Base类。如果我们只是不想要子类的公共构造函数但是保持对象图不变,则可以使用工厂模式来按需创建它们。但即使在这种情况下,也必须将工厂返回的对象强制转换为Derivate1Derivate2以使用(非静态)方法。


我想我知道他们想听到什么,共同的建议是“赞成作文而不是继承”。因此,不要说 Derivate1是一个基础,而是执行 Derivate1有一个基础

public class Derivate1 {
  private Base base;

  // ... more
}

public class Derivate2 {
  private Derivate1 derivate1;

  // ... more
}

不再继承,Derivates仍然可以使用以前的超类的方法。

答案 2 :(得分:2)

根据他们给你的提示,我认为答案是适配器模式,有时会用于遗留代码。

你可以在这看一下:

http://en.wikipedia.org/wiki/Adapter_pattern

答案 3 :(得分:1)

我们可以做两件事:

  • 我们可以将Derivate1Derivate2的某些方法提升为Base,这是有道理的(如上所述)
  • 我们可以同时制作Derivate1Derivate2 abstract:这会阻止实例化,但不会继承

答案 4 :(得分:0)

我认为他们的意思是将衍生物提取到接口

答案 5 :(得分:0)

如果有意义,您可以直接在基类中包含这些方法。但这当然取决于这门课程的意义。如果可能,您可以在实用程序类中使用静态方法。顺便说一下,在这两种情况下,您的开发人员都必须改变对API的使用。

答案 6 :(得分:0)

第一个显而易见的事情是层次结构中的每个类都是具体的 - 通常,类型应该是抽象的,或者是叶子类型。其次,关于这些方法是什么的信息还不够 - 如果它们覆盖了Base或Derived1中的某些东西,你就无法将它们移动到Base中;如果它们是适用于任何Base的实用程序方法,那么它们可能会被移动到Base中,如果它们独立于Base,那么它们可以被移动到辅助类或策略中。

但我会质疑一个类不是必需的,但它的行为是 - 这有点暗示提问者正在设计一个本体而不是一个面向对象的程序 - 一个类存在的唯一原因是提供行为并且一致地封装有用的行为是类存在的充分必要条件。

答案 7 :(得分:0)

由于您不拥有派生类,因此无法删除它们。基类是你的全部,所以你有控制权。客户是你的,所以你有控制权。因此,最好的方法是拥有一个暴露给客户端的全新类。这个类实际上创建了派生实例(注意:你的客户端不再处理它)并使用它们的有用功能。