在继承中,如果子类不遵守所有超类行为,该怎么办?

时间:2013-07-10 13:25:18

标签: java oop inheritance

就像有一个哺乳动物类有行走的行为,所有子类都应该遵守。

但很少有像海豚和蝙蝠这样的哺乳动物没有这种行为。

我们如何实现这个目标?

按照我的说法,所有子类都应该遵守与超类相关的所有行为。

感谢任何帮助。谢谢!

8 个答案:

答案 0 :(得分:6)

哺乳动物类应该只为所有哺乳动物定义共同的特征,正如你所说,行走不是一个常见的特征。

可以使用接口添加行为,如下例

class abstract Mammal {

    abstract void regulateTemperature();

}

interface CanFly {

    void land();
    void takeOff();

}

class Bat extends Mammal implements CanFly {

}

很抱歉,如果我犯了语法错误,我的Java有点生疏,但是你有了这个想法,就像你在基类中一样通用。这就是说我同意@dystroy,在动物领域获得继承是很困难的。你可能想尝试一下灯或衬衫的造型,从比这更简单的方法开始。

答案 1 :(得分:2)

你的断言相互矛盾。

  • 就像有一个哺乳动物类有行走的行为,所有子类都应该遵守。
  • 但很少有像海豚和蝙蝠这样的哺乳动物没有这种行为。

要么所有子类都有行为,要么都没有行为。你不能兼得。

在面向对象的设计中,所有子类都支持其超类的契约是很有用的,这样任何子类的实例都可以在引用超类的任何地方使用。这称为Liskov substitution principle

答案 2 :(得分:2)

您刚刚发现了传统继承和OOP概念的根本问题。即使是最微不足道的例子,对象分类为严格的类别也是非常困难的(有趣的是,分类是智商测试的重要组成部分)。在研究动物王国的例子时,很快就会发现,将时间分组为严格的,自上而下的,细分的类别是没有意义的。将这个想法与编程相结合并尝试重用功能,最终可能会自杀。

现代OOP避免使用继承进行代码重用,而是将其用于多态。深度遗传树很脆弱,被认为是不好的做法。代码重用是通过聚合完成的。混合并匹配小对象及其行为以创建更复杂的对象。使用依赖注入和基于策略的设计等概念可以增强此行为。

有关这些概念的更多信息和实际应用,请阅读:

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

http://en.wikipedia.org/wiki/Aspect-oriented_programming

http://en.wikipedia.org/wiki/Component-based_software_engineering

http://en.wikipedia.org/wiki/Policy-based_design

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

答案 3 :(得分:0)

简单,使用Walking界面,可用于行走的动物。

例如:

interface Walking {
    public abstract void walk();  // implementing classes must implement this
}

class Cow extends Mammal implements Walking {
    public void walk() { ... }
}

class Dolphin extends Mammal {
    public void swim() { ... }
}

class Bat extends Mammal {
    public void fly() { ... }
}

答案 4 :(得分:0)

在你的例子中没有正确定义哺乳动物类,因为并非所有的哺乳动物都可以行走。它不应包含walk方法。在这种情况下,我会选择步行界面,其中游泳和飞行界面也适用于其他用于移动的方法。

答案 5 :(得分:0)

如果你将Mammal定义为使用Walk()方法,那么你就说所有的哺乳动物都可以走路了。

您对Dolphin的实施可能如下所示:

public void Walk()
{
    throw new TraitLossException();
}

http://www.nescent.org/science/awards_summary.php?id=24

答案 6 :(得分:0)

免责声明:这个答案不是关于良好的设计,而是关于现有的实践。

有时候,你有一个不能(或根本不会)提供超类提供的所有服务的子类。一个突出的例子是Iterator.remove(),它可以实现也可以不实现。当标准库中出现这种情况时,通常会抛出UnsupportedOperationException。在某些情况下,就像Iterator一样,在某种意义上,即使是不支持该操作的实现也应该抛出异常,甚至是合同的一部分。

答案 7 :(得分:0)

这是将非抽象类子类化可能有意义的情况之一。

class Mammal {
    ...
    /** May not walk. This implementation succeeds. */
    void walk() {
        ... do some walking ...
    }
}

class WateronlyMammal extends Mammal {
    @Override void walk() {
        ... sit there looking sad ...
    }
}

然后将动物类型设为new Mammal("Dog")new WateronlyMammal("Dolphin")

替代方案,您可能需要合成而不是继承,这会为更简单的组件进行冗长交换。

 interface Walker {
     /** May not walk. */
     void walk();
 }
 final class Mammal {
     public Mammal(String speciesName, Walker walk) {
         ...
     }
     ...
 }

创建为new Mammal("Dog", competentWalker())new Mammal("Dolphin", notSoGoodWalker())

甚至可以添加便利构造函数:

     public Mammal(String speciesName) {
         this(speciesName, competentWalker(), poorFlyer());
     }

(注意我们在这里对物种类型和特定动物存在一些混淆。另外值得注意的是,如果你采取任何曾经存在的动物,就没有物种界限。)