简体   繁体   English

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

[英]How to give a child class a modified inherited method?

I'm facing a trouble finding the best OOP design solution to the following problem: I have the parent abstract class Classifier which includes the abstract method classify(Instances dataset) . 我面临着以下问题的最佳OOP设计解决方案的麻烦:我有父抽象类Classifier ,其中包括抽象方法classify(Instances dataset) Two classes extends Classifier , namely NormalClassifier and ThresholdClassifier . 两个类扩展了Classifier ,即NormalClassifierThresholdClassifier Both the children classes implements the classify(Instances dataset) method. 这两个子类均实现classify(Instances dataset)方法。 However, ThresholdClassifier requires the classify(Instances dataset) method to be of this form classify(Instances dataset, double threshold) and can't never work with classify(Instances dataset) . 但是, ThresholdClassifier要求classify(Instances dataset)方法具有这种形式classify(Instances dataset, double threshold)并且永远不能与classify(Instances dataset)

Note that ThresholdClassifier can't accept the threshold parameter in its constructor and it must have the parameters in the classify method. 请注意, ThresholdClassifier不能在其构造函数中接受threshold参数,并且必须在classify方法中具有该参数。

In this case the child class ThresholdClassifier share the same characteristic as the parent but it requires a different method signature. 在这种情况下,子类ThresholdClassifier与父类具有相同的特征,但是需要不同的方法签名。 I'm not able to extend the parent class because it would require me to implement the original method signature nor it makes sense not to extend the parent class because it's clearly a Classifier . 我无法扩展父类,因为这将要求我实现原始方法签名,也不能扩展父类,因为它显然是Classifier这是没有道理的。 So how would one solve such a design problem in Java OOP? 那么如何解决Java OOP中的这种设计问题呢? Is there a technical term for this issue? 这个问题有技术术语吗?

Edit 1: 编辑1:

what I basically did to solve this issue is that I created an interface called ThresholdBasedClassifier that contains the method setThreshold(double threshold) . 解决此问题的基本方法是创建一个名为ThresholdBasedClassifier的接口,其中包含方法setThreshold(double threshold) Then I made ThresholdClassifier implement this method and created an internal field called threshold . 然后,我使ThresholdClassifier实现此方法,并创建了一个称为threshold的内部字段。 However, I find this to be an ugly design solution for many reasons, especially that the user could forget that he needs to set change or set the threshold before calling classify(Instances dataset) 但是,由于许多原因,我发现这是一个丑陋的设计解决方案,尤其是用户可能忘记了自己需要在调用classify(Instances dataset)之前设置更改或设置阈值

Edit 2: 编辑2:

Also the requirements says that there can't be a default value for the threshold . 此外,要求还指出, threshold值不能有默认值。

Edit 3: 编辑3:

My example above was just an example to a common design problem I'm facing in general. 我上面的示例只是我通常遇到的常见设计问题的示例。 So I'm looking for a general solution not a specific solution. 因此,我在寻找通用解决方案而不是特定解决方案。

I can see multiple solutions: 我可以看到多种解决方案:

  1. Make ThresholdClassifier extends from NormalClassifier . 使ThresholdClassifierNormalClassifier扩展。

  2. Change Classifier to a concrete class (remove abstract). Classifier更改为具体类(删除摘要)。

  3. Implement classify(Instances dataset) on ThresholdClassifier calling the classify(Instances dataset, double threshold) with a default threshold value. ThresholdClassifier上实现classify(Instances dataset) classify(Instances dataset, double threshold)并使用默认threshold值调用classify(Instances dataset, double threshold)

For example: 例如:

void classify(Instances dataset) {
    classify(dataset, 10);
}
  1. Make two empty methods on Classifier , so each one overrides the apropriate one: Classifier上创建两个空方法,因此每个方法都会覆盖适当的方法:

Code: 码:

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
    }
}

You can even throw an exception inside Classifier methods. 您甚至可以在Classifier方法内引发异常。 This will enforce the implementation on the child class. 这将在子类上强制实施。

As ThresholdClassifier "can't never work with classify(Instances dataset) ", I think this method shouldn't be declared in Classifier abstract class. 由于ThresholdClassifier “永远无法使用classify(Instances dataset) ”,我认为不应在Classifier抽象类中声明此方法。 You should remove classify method from Classifier and declare classify(Instances dataset) in NormalClassifier and classify(Instances dataset, double threshold) in ThresholdClassifier . 您应从Classifier删除classify方法,并在NormalClassifier声明classify(Instances dataset) ,并在ThresholdClassifier声明classify(Instances dataset) classify(Instances dataset, double threshold)

ThresholdClassifier should contain an internal value double threshold which allows it to define: ThresholdClassifier应该包含一个内部值double threshold ,该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
}

Additional Info 附加信息

Are you asking for a general signature? 您是否要求一般签名? Which I think is worthless because it means that for each different type there will be different interfaces which means you won't get very much reuse out of defining it this way which completely defeats the purpose of using a class hierarchy, interfaces, and abstract classes. 我认为这毫无用处,因为这意味着对于每种不同的类型,都会有不同的接口,这意味着通过这种方式定义它不会有太多重用,这完全破坏了使用类层次结构,接口和抽象类的目的。 Nevertheless there are such methods in Java. 尽管如此,Java中还是有这样的方法。 You would need something like the following: 您将需要以下内容:

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

Then your ThresholdClassifier would look something like this: 然后您的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
    }

You may be able to make the above an abstract class and require a method void classify(final Instances dataset, final double threshold) (I'm not totally sure--it may be considered ambiguous since the double threshold could be interpreted as either a double or a Double ). 您可能可以将上面的内容做成一个抽象类,并需要一个方法void classify(final Instances dataset, final double threshold) (我不太确定,由于double threshold可以解释为一个doubleDouble )。

You may also consider making the options explicitly be String instead of Object . 您也可以考虑将选项显式设置为String而不是Object This at least would allow you to make a general command line driver. 这至少可以使您制作一个通用的命令行驱动程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM