[英]How to give a child class a modified inherited method?
我面临着以下问题的最佳OOP设计解决方案的麻烦:我有父抽象类Classifier
,其中包括抽象方法classify(Instances dataset)
。 两个类扩展了Classifier
,即NormalClassifier
和ThresholdClassifier
。 这两个子类均实现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:
我上面的示例只是我通常遇到的常见设计问题的示例。 因此,我在寻找通用解决方案而不是特定解决方案。
我可以看到多种解决方案:
使ThresholdClassifier
从NormalClassifier
扩展。
将Classifier
更改为具体类(删除摘要)。
在ThresholdClassifier
上实现classify(Instances dataset)
classify(Instances dataset, double threshold)
并使用默认threshold
值调用classify(Instances dataset, double threshold)
。
例如:
void classify(Instances dataset) {
classify(dataset, 10);
}
Classifier
上创建两个空方法,因此每个方法都会覆盖适当的方法: 码:
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
}
}
您甚至可以在Classifier方法内引发异常。 这将在子类上强制实施。
由于ThresholdClassifier
“永远无法使用classify(Instances dataset)
”,我认为不应在Classifier
抽象类中声明此方法。 您应从Classifier
删除classify
方法,并在NormalClassifier
声明classify(Instances dataset)
,并在ThresholdClassifier
声明classify(Instances dataset)
classify(Instances dataset, double threshold)
。
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
}
附加信息
您是否要求一般签名? 我认为这毫无用处,因为这意味着对于每种不同的类型,都会有不同的接口,这意味着通过这种方式定义它不会有太多重用,这完全破坏了使用类层次结构,接口和抽象类的目的。 尽管如此,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
可以解释为一个double
或Double
)。
您也可以考虑将选项显式设置为String
而不是Object
。 这至少可以使您制作一个通用的命令行驱动程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.