如何给子类一个修改后的继承方法?

时间:2015-04-26 05:29:53

标签: java oop

我遇到了解决以下问题的最佳OOP设计解决方案的问题:我有父抽象类Classifier,其中包含抽象方法classify(Instances dataset)。两个类扩展Classifier,即NormalClassifierThresholdClassifier。子类都实现了classify(Instances dataset)方法。但是,ThresholdClassifier要求classify(Instances dataset)方法的格式为classify(Instances dataset, double threshold),并且不能与classify(Instances dataset)一起使用。

请注意,ThresholdClassifier无法在其构造函数中接受threshold参数,并且必须在classify方法中包含参数。

在这种情况下,子类ThresholdClassifier与父类具有相同的特征,但它需要不同的方法签名。我无法扩展父类,因为它需要我实现原始方法签名,也没有理由不扩展父类,因为它显然是Classifier。那么如何在Java OOP中解决这样的设计问题呢?这个问题有技术术语吗?

修改1:

我基本上为解决这个问题所做的是创建了一个名为ThresholdBasedClassifier的接口,其中包含方法setThreshold(double threshold)。然后我让ThresholdClassifier实现了这个方法并创建了一个名为threshold的内部字段。但是,由于许多原因,我发现这是一个丑陋的设计解决方案,尤其是用户可能忘记在调用classify(Instances dataset)之前需要设置更改或设置阈值

编辑2:

此外,要求表明threshold

没有默认值。

编辑3:

上面的例子只是我面临的一个常见设计问题的一个例子。所以我正在寻找一个通用的解决方案,而不是一个特定的解决方案。

3 个答案:

答案 0 :(得分:1)

我可以看到多种解决方案:

  1. ThresholdClassifier延伸至NormalClassifier

  2. Classifier更改为具体类(删除摘要)。

  3. classify(Instances dataset)上实施ThresholdClassifier,使用默认classify(Instances dataset, double threshold)值调用threshold

  4. 例如:

    void classify(Instances dataset) {
        classify(dataset, 10);
    }
    
    1. Classifier上创建两个空方法,因此每个方法都会覆盖适当的方法:
    2. 代码:

      public abstract class Classifier {
          void classify(Instances dataset) {
          }
          void classify(Instances dataset, double threshold) {
          }
      }
      
      public class NormalClassifier extends Classifier {
          void classify(Instances dataset) {
              // Code here
          }
      }
      
      public class ThresholdClassifier extends Classifier {
          void classify(Instances dataset, double threshold) {
              // Code here
          }
      }
      

      您甚至可以在分类器方法中引发异常。这将强制执行子类的实现。

答案 1 :(得分:0)

由于ThresholdClassifier"无法使用classify(Instances dataset)",我认为此方法不应在Classifier抽象类中声明。 您应该从classify移除Classifier方法,并在classify(Instances dataset)NormalClassifierclassify(Instances dataset, double threshold)声明ThresholdClassifier

答案 2 :(得分:-1)

ThresholdClassifier应包含内部值double threshold,允许它定义:

private double threshold = DEF_THRESHOLD;

public void setThreshold(final double threshold){
    this.threshold = threshold;
}

@Override
public void classify(Instances dataset){
    this.classify(dataset, threshold);
}

private void classify(Instances dataset, final double threshold){
    // TODO implement this classify method
}

其他信息

您是否要求签名?我认为这是毫无价值的,因为它意味着对于每种不同的类型都会有不同的接口,这意味着你不会以这种方式重新定义它,这完全违背了使用类层次结构,接口和抽象类的目的。然而,Java中有这样的方法。您需要以下内容:

public abstract void classify(final Instances dataset, 
    final Object... options) throws IllegalArgumentException

然后你的ThresholdClassifier看起来像这样:

public ThresholdClassifier extends Classifier{
    @Override
    public void classify(final Instances dataset, 
        final Object... opts) throws IllegalArgumentException {
    if(opts.length != 1)
        throw new IllegalArgumentException(); // probably should say something

    try{
        // casts from Double to double automatically
        final double threshold = (Double)opts[0];
        // TODO implement classify method
        //  ...
    }catch(ClassCastException cce){
        throw new IllegalArgumentException();// should probably say something
    }

您可以将上面的内容变成一个抽象类,并且需要一个方法void classify(final Instances dataset, final double threshold)(我不完全确定 - 因为double threshold可以被解释为一个,所以它可能被认为是模棱两可的doubleDouble)。

您还可以考虑明确将选项设为String而不是Object。这至少可以让你制作一个通用的命令行驱动程序。