【发布时间】:2011-04-16 21:19:48
【问题描述】:
我的问题与 API 设计有关。
假设我正在设计一个向量(数学/物理含义)。我想要一个不可变的实现和一个可变的实现。
然后我的向量看起来像这样:
public interface Vector {
public float getX(); public float getY();
public X add(Vector v);
public X subtract(Vector v);
public X multiply(Vector v);
public float length();
}
我想知道如何确保同时拥有可变和不可变的实现。我不太喜欢 java.util.List 的方法(默认允许可变性)和 Guava 的不可变实现所具有的 UnsupportedOperationException()。
如何设计一个“完美”的接口或抽象类 Vector 与这两种实现?
我想过这样的事情:
public interface Vector {
...
public Vector add(Vector v);
...
}
public final class ImmutableVector implements Vector {
...
public ImmutableVector add(Vector v) {
return new ImmutableVector(this.x+v.getX(), this.y+v.getY());
}
...
}
public class MutableVector implements Vector {
...
public MutableVector add(Vector v) {
this.x += v.getX();
this.y += v.getY();
return this;
}
...
}
总而言之,我想检查一下这种方法是否存在明显的设计缺陷,它们是什么,我应该怎么做才能修复这些?
注意:“向量”是一个更一般用例的示例。为了我的问题,我本可以选择重写 List 接口或其他任何东西。请关注更一般的用例。
最终选择,在下面的答案之后,基于 Joda-time,正如有人解释但现在已编辑:
/** Basic class, allowing read-only access. */
public abstract class ReadableVector {
public abstract float getX(); public abstract float getY();
public final float length() {
return Vectors.length(this);
}
// equals(Object), toString(), hashCode(), toImmutableVectors(), mutableCopy()
}
/** ImmutableVector, not modifiable implementation */
public final class ImmutableVector extends ReadableVector implements Serializable {
// getters
// guava-like builder methods (copyOf, of, etc.)
}
/** Mutable implementation */
public class Vector extends ReadableVector implements Serializable {
// fields, getters and setters
public void add (ReadableVector v) {/* delegate to Vectors */}
public void subtract(ReadableVector v) {/* delegate to Vectors */}
public void multiply(ReadableVector v) {/* delegate to Vectors */}
}
/** Tool class containing all the logic */
public final class Vectors {
public static ImmutableVector add(ReadableVector v1, ReadableVector v2) {...}
public static void addTo(Vector v1, ReadableVector v2) {...}
...
}
我将 Vector 从接口更改为抽象类,因为基本上矢量不应该是其他任何东西。
谢谢大家。
【问题讨论】:
-
添加不添加而是返回新对象的方法?不理想!
-
这叫流畅的界面,丰富。风靡一时。它确实添加了 - 再看一遍。
-
同时拥有一个可变和不可变的接口实现会引入一个问题,如果一个对象是不可变的,而不在您的代码中回溯,您就无法依赖这个问题。如果它是一个返回对象的 3:rd 方库,这将成为一个更大的问题。您可能最终不得不将所有对象视为潜在可变的,从而使不可变实现变得多余。如果您通过向量接口的可变和不可变实现来解释您要解决的问题,那么我们可以帮助您通过更简洁的设计来解决这个问题。
标签: java class-design immutability mutable