【问题标题】:When we override a method we should use all the parameters that are in the method signature?当我们重写一个方法时,我们应该使用方法签名中的所有参数吗?
【发布时间】:2015-12-28 03:23:41
【问题描述】:

我发现一些覆盖方法没有使用方法签名中的所有参数。

例如:

@Override
protected void setSomething(Object a, Object b, Object c) {
    this.a = a
    this.b = b;
    // the parameter c is not used (ignored)
}

通常父类不应该关心子类将如何实现抽象方法。

但是在MHO中,要使用方法的参数,当子类实现不需要参数时,这是非常罕见的,当这种情况发生时,可能是接口的设计或抽象的设计有问题类。

一个功能的基础是:输入->输入过程->输出。

有时您需要计算这些输入,但如果您在函数的过程中不使用其中的一些输入,则不应将这些输入作为函数的输入。

你可以跳过这些输入的计算,调用一个使用所有输入的精确函数,所以是精确函数。

这种情况可以接受的唯一情况是,当我们不想要父类的行为时,我们可以这样写:

@Override
protected void setSomething(Object a, Object b, Object c) {
      //Nothing to do
}

或者

@Override
 protected void setSomething(Object a, Object b, Object c) {
  throw new UnsupportedOperationException(...);
}

声纳说:

未使用的参数具有误导性。无论传递给此类的值如何 参数是,行为将是相同的。

我的问题是: 当我们重写一个方法时,我们应该使用方法签名中的所有参数吗?

当我说“使用所有参数”时,我试图说方法签名中的所有参数实际上都在方法的主体(实现)中使用。

【问题讨论】:

  • “我发现一些覆盖方法没有使用方法签名中的所有参数”你在哪里看到过这个?
  • “当我们重写一个方法时,我们应该使用方法签名中的所有参数吗?”。当然不。为什么子类需要所有参数?
  • 原谅我,我想我误解了你。我认为您的意思是简单地传递了参数但被忽略了?如果是这种情况,那很好,您不必对参数做任何事情。最初我以为你的意思是超类和子类方法的签名不匹配,这是不可能的。
  • @Neilos 我用一个例子更新了我的问题,是的,重点是,忽略覆盖方法主体中的参数
  • @JesusZavarce 这可能表明有问题,是的,但也可能不是问题。每个案例都必须根据具体情况进行评估,但一般来说,没有普遍的规则说它不好,事实上我可以想到你肯定希望接口实现特定签名但具体类会忽略该参数,但其他实现不会忽略该参数。

标签: java


【解决方案1】:

需要使用所有参数吗?不会。您经常会看到以下示例:

@Override
public void doFoo(String thingy) {
  // no-op
}

或者

@Override
public void doFoo(String thingy) {
  throw new UnsupportedOperationException(...);
}

但两者都是某处设计存在问题的标志。例如,java.util.List 甚至 java.util.Iterable 都通过提供变异方法排除了不可变集合的可能性。不可变的实现必须抛出UnsupportedOperationException

【讨论】:

  • 是的,我同意你的观点,当你不想要父类的一种方法的行为时,你可以使用 @Override public void doFoo(String thingy) { // nothing to do } 但我的问题是关于将代码放入覆盖方法中的情况,并且您忽略了一些输入参数。
  • 这是一个不同的情况,但同样适用。如果你有一个接口Dog 和一个方法void barkAt(Creature),并且你有一个名为CrazyDog 的实现,它使用barkAtInternal(this); 之类的东西来实现这个方法,(即对自己咆哮,完全忽略Creature 它应该吠)这是完全有效的。它只是开始提出一些关于 API 本身的问题,而不是你的实现。
【解决方案2】:

正如您所说:“我们应该”——但我们不必这样做。有时一个实施方法甚至会抛出一个RuntimeException,例如Java 集合框架的UnsupportedOperationException

【讨论】:

    【解决方案3】:

    当我们重写一个方法时,我们应该使用方法签名中的所有参数吗?

    当您覆盖一个方法时,被覆盖的方法必须定义与超方法相同的参数。

    您没有义务使用实现中的所有参数 - 这取决于您希望通过此实现实现的目标,有时可能不需要所有参数。

    但是,在方法实现中包含未使用的方法参数是设计不佳的标志。当定义一个方法(被abstract或实现)时,你应该尝试回答“我为什么需要这个参数?”“这个参数会一直被使用吗?”。如果在实现中可能会出现某些参数不会被使用的情况,那么您可以定义一些重载方法。

    以这个例子为例。让我们有这个方法

    void someMethod(String first, String optionalParameter) { ... }
    

    第二个参数是可选的(即可能需要也可能不需要)- 当不需要该参数时,您可以传递 null 或任何其他参数。在这种情况下,我会重载两个方法

    void someMethod(String first) { ... }
    
    void someMethod(String first, String second) { ... }
    

    我也会确保所有的参数都用在相应的实现中。

    【讨论】:

    • 你也这么认为吗? DocumentFilter 设计不好?如何做得更好?对每个可能不需要的参数都有一个重载的方法?很难预测将总是需要哪些参数。
    • @xehpuk,我相信 Swing 中 DocumentFilter 的实现使用了所有参数。您可以在不关心某些参数值的情况下实现他们的方法,这不是设计师的错。他们不应该关心这一点 - 他们应该只提供解释所有参数的含义。但是,当您设计一个将在您的系统中实际实现的接口时,您可以对是否需要某个参数做出相当不错的预测。
    • 嗯,有应用程序的设计,还有框架或库的设计。另一个例子是Observer,其中update 方法的第二个参数通常不需要。在Observable 中甚至还有一个无参数方法notifyObservers,它为第二个参数生成null
    【解决方案4】:

    如果你重写了一个方法,那么你必须使用所有的参数。

    但是你也可以重载一个方法——写一个同名但参数不同的方法。所以如果你不使用所有的参数,你就是在重载,而不是覆盖。

    class Accessor {
    
        public void doSomething(String attr) {}
    
    }
    
    class Child extends Accessor {
    
        // This is overriding
        @Override
        public void doSomething(String attr) {
           // ...
        }
    
        // This is overloading
        public void doSomething() {
           // ...
        }
    }
    

    【讨论】:

    • 我认为 OP 意味着我们是否真的必须在 attr 的正文中使用 attr 做某事(评估它,分配新值,...)
    • 有可能,我在编辑问题之前就已经回答了。
    猜你喜欢
    • 2016-09-05
    • 2020-06-06
    • 1970-01-01
    • 2016-01-10
    • 2014-04-09
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    相关资源
    最近更新 更多