我遇到了解决以下问题的最佳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:
上面的例子只是我面临的一个常见设计问题的一个例子。所以我正在寻找一个通用的解决方案,而不是一个特定的解决方案。
答案 0 :(得分:1)
我可以看到多种解决方案:
让ThresholdClassifier
延伸至NormalClassifier
。
将Classifier
更改为具体类(删除摘要)。
在classify(Instances dataset)
上实施ThresholdClassifier
,使用默认classify(Instances dataset, double threshold)
值调用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
}
}
您甚至可以在分类器方法中引发异常。这将强制执行子类的实现。
答案 1 :(得分:0)
由于ThresholdClassifier
"无法使用classify(Instances dataset)
",我认为此方法不应在Classifier
抽象类中声明。
您应该从classify
移除Classifier
方法,并在classify(Instances dataset)
和NormalClassifier
中classify(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
可以被解释为一个,所以它可能被认为是模棱两可的double
或Double
)。
您还可以考虑明确将选项设为String
而不是Object
。这至少可以让你制作一个通用的命令行驱动程序。