处理仅对层次结构的一部分有意义的二进制操作

时间:2010-05-05 13:44:01

标签: java oop

我有一个层次结构,我将大大简化,接口Value的实现。假设我有两个实现,NumberValue和StringValue。

有一个平均操作只对NumberValue有意义,带有签名

NumberValue average(NumberValue numberValue){ ... }

在创建这些变量并在各种集合中使用它们之后的某个时刻,我需要平均一个我知道只有NumberValue类型的集合,我认为有三种可能的方法:

  1. 非常复杂的通用签名,它在编译时保留类型信息(我现在正在做什么,导致代码难以维护)
  2. 将操作移至Value级别,并且:为StringValue抛出一个unsupportedOperationException,并为NumberValue进行强制转换。
  3. 在我确定我有一个NumberValue的位置进行投射,使用稍微复杂的泛型来确保这一点。
  4. 有没有人有更好的想法,或者有关oop最佳做法的建议?

3 个答案:

答案 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子句来区分NumberValueStringValue,以确定是否要调用average。所以我不明白这会更复杂。层次结构有意义 - AveragableValue s是Value的子类型,NumberValueAveragableValue的类型。

但是,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扩展。