我有一个层次结构,我将大大简化,接口Value的实现。假设我有两个实现,NumberValue和StringValue。
有一个平均操作只对NumberValue有意义,带有签名
NumberValue average(NumberValue numberValue){ ... }
在创建这些变量并在各种集合中使用它们之后的某个时刻,我需要平均一个我知道只有NumberValue类型的集合,我认为有三种可能的方法:
有没有人有更好的想法,或者有关oop最佳做法的建议?
答案 0 :(得分:1)
正如@tafa所说,在我看来,界面将是一个不错的选择。根据您对average
的签名,我提出了以下内容。
<强> AveragableValue 强>
public interface AveragableValue<T> extends Value
{
public T average(T value);
}
<强> NumberValue 强>
public class NumberValue implements AveragableValue<NumberValue>
{
private int _n;
public NumberValue(int n)
{
this._n = n;
}
@Override
public void doSomething()
{
// from Value interface
}
@Override
public NumberValue average(NumberValue value)
{
return new NumberValue((this._n + value._n) / 2);
}
}
然后,您可以将您的收藏集设为AveragableValue
类型。在您的代码中,您必须在某个地方使用某种if/else
子句来区分NumberValue
和StringValue
,以确定是否要调用average
。所以我不明白这会更复杂。层次结构有意义 - AveragableValue
s是Value
的子类型,NumberValue
是AveragableValue
的类型。
但是,average
的签名看起来不正确。它只需要2个值(this
和参数)并对它们求平均值。然后,您将丢失之前已平均的事物的总数。所以假设整数为值(就像我一样),像这样:
(new NumberValue(4)).average(new NumberValue(8)).average(new NumberValue(12));
会为您提供值9
而不是8
。这是你想要的吗?它使得迭代完成的许多计算变得很糟糕,就像你可能正在使用集合一样。
如果你向我们展示你的一些代码 - 如何使用这些类,包含它们的集合,你现在如何进行平均 - 我可以给出更好的答案。
答案 1 :(得分:0)
我会创建另一个接口IAveragable,它包含从Value派生的平均操作。然后StringValue只实现Value接口,NumberValue将实现IAveragable。
然后当需要使用平均操作时,我会检查对象是否实现了IAveragable。
答案 2 :(得分:0)
我无法发表评论,因此我会发布一个新答案。
为值创建一个接口:
public interface Value<T> {
public T getValue();
}
其中一个是可以理解的:
public interface Averagable<T> {
public T average(T value);
}
然后数字值将是:
public class NumberValue implements Averagable<Number>, Value<Number>{
public Number average(Number value) {
// do your stuff
}
public Number getValue() {
// do your stuff
}
}
没有必要让Averagable从Value扩展。