覆盖非抽象方法是否是一种好的实践方式?

13
我有一个情况,需要修改父类方法以实现子类特定的逻辑,但是该方法的逻辑对于所有其他子类都相同。
我的两个选项:
1)将该方法设为抽象的,并为每个除了我关注的子类以外的子类重复相同的代码。
2)在关注的子类中覆盖非抽象方法,在那里我想要修改逻辑。
Java中覆盖非抽象方法好吗?概念上,覆盖非抽象方法与抽象方法有什么区别?

1
“在Java中覆盖非抽象方法是一个好的实践吗?” 是的。 - Andreas
1
你确定继承是在这里正确的方式吗? 在决定之前,我建议你阅读此文章:链接 - Kraylog
4个回答

11

在一定程度上,这是一个风格问题。

这是一个普遍的做法 - 但也有人告诉你,任何方法都不应该有超过一个实现。这些人声称,在继承层次结构中存在多个实现会导致很难调试的代码 - 因为您必须非常小心地确定实际调用了哪个版本的这种方法。

当其他方法大量使用此类方法时,您可能会很容易失去大局 - 突然间,因为一些子类中的重写而变得复杂,很难预测某些代码正在执行什么操作。

理解的关键:在 X 类中,某个方法 foo() 的“单一” @Override 是可以的、普遍的、良好的做法。但是在 X 的子类中再次覆盖相同的 foo() - 这可能很快引起各种问题。

换句话说:仔细处理重新实现非抽象方法。如果它使您的代码难以理解,请寻找其他解决方案。例如:基类具有一个固定(final)方法来执行操作 - 该方法调用其他 抽象 方法来完成其工作。示例:

public abstract class Base {
  public final int doSomething() {
    String tmp = foo();
    int result = bar(tmp);
    return result * result;
  }
  public abstract String foo();
  public abstract int bar(String str);

正如所写:在这里,您可以看到由于doSomething()是final,因此实现是“固定的”,但必须在每个子类中覆盖所需的“配料”。


我并没有完全理解最后一句话,请您能否举个例子来说明这个语句:“比如:基类有一个固定的(final)方法来完成任务 - 这个方法会调用其他抽象方法来实现它的功能。” - Learner

9

在Java中覆盖非抽象方法是一种好的实践吗?

是的。(但请确保您没有违反Liskov替换原则(参考现有的SO帖子),该原则告诉子类不应该破坏父类类型定义。例如,从Animal类重写的walk()方法应该执行(具有)行走的行为,它不应该执行飞行或其他行为。)

我还建议您阅读SOLID原则以了解设计原则。

覆盖非抽象方法和抽象方法在概念上有什么区别。

据我所知,没有区别。但是,为了明确起见,抽象方法不包含任何实现,您必须进行覆盖,而非抽象方法可以被覆盖。


1
覆盖非抽象方法是完全可以的,并且通常被使用,只要你不违反Liskov Substitution principle原则: Liskov原则对签名有一些标准要求: - 子类型中方法参数的逆变性。 - 子类型中返回类型的协变性。 - 子类型的方法不应该抛出新的异常,除非这些异常本身就是超类型方法抛出的异常的子类型。
除了签名要求之外,子类型还必须满足一些行为条件: - 前置条件不能在子类型中变得更强。 - 后置条件不能在子类型中变得更弱。 - 超类型的不变式必须在子类型中保持不变。 - 历史约束(“历史规则”)。对象仅通过其方法(封装)被认为是可修改的。因为子类型可能会引入超类型中不存在的方法,所以引入这些方法可能允许在子类型中进行状态更改,而这在超类型中是不允许的。历史约束禁止这种情况的发生。
只要方法在被覆盖后仍然遵守合同,就不应该对新实现的功能感到困惑。方法的新实现应该仍然遵守之前被覆盖之前的实现相同的合同。

1

在相关的子类中覆盖非抽象方法,以便我想要更改逻辑 - 是的

例如: 如果您考虑Object类中的toString()和hashCode()方法,这两种方法都是非抽象方法,但通常建议在子类中覆盖这些方法。

因为如果我想执行自己的逻辑而不是超类的逻辑,需要覆盖并使用它,在这种情况下建议进行覆盖。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接