【发布时间】:2012-04-27 14:54:23
【问题描述】:
我想在java中创建可变节点和不可变节点,除了可变节点之外,两者都应该相同。如何实现可变类和不可变类的基类和两个派生类?
【问题讨论】:
-
这是什么“节点”?上下文是什么?这些类应该开放继承吗?
标签: java oop immutability mutable
我想在java中创建可变节点和不可变节点,除了可变节点之外,两者都应该相同。如何实现可变类和不可变类的基类和两个派生类?
【问题讨论】:
标签: java oop immutability mutable
可变类和不可变类之间的区别在于,不可变类没有设置器或任何其他修改内部状态的方法。状态只能在构造函数中设置。
调用父类 Immutable 是个坏主意,因为当您有子类时,这将不再适用。该名称会产生误导:
ImmutableNode node = new MutableNode();
((MutableNode)node).change();
【讨论】:
您需要做的就是创建一个带有受保护变量的基类
public class Base{
protected int foo;
}
可变的需要能够设置变量
public class MutableBase extends Base{
public void setFoo(){}
}
不可变对象只需要设置一次变量
public class ImmutableBase extends Base{
public ImmutableBase(int foo){
this.foo = foo;
}
}
大多数不可变类都有方法来作用于内部的变量而不改变实例。字符串这样做,你可能想要这样的东西
public ImmutableBase add(int bar){
return new ImmutableBase(this.foo+bar);
}
这很酷的一点是,您可以让您班级的用户更少控制/担心每个实例的内部结构。这使得使用起来更容易,因为在 Java 中,所有内容都是通过对象引用传递的,所以如果您传递的是 String 或 ImmutableBase,您不必担心它会被更改。
【讨论】:
foo 不能是私人的。
不可变类是一个一旦创建就不能改变其内容的类。不可变对象是状态不能改变的对象。
Java 中不可变类的一个常见示例是String class。
【讨论】:
对于一个不可变的类,它必须被声明为 final,并且它不能有 setter 方法。最终声明确保它不能被扩展和添加额外的可变属性。
class Base {
protected int var1;
protected int var2;
public getVar1() {return var1;}
public getVar2() {return var2;}
}
class Mutable extends Base {
public setVar1(int var1) {this.var1 = var1}
public setVar2(int var2) {this.var2 = var2}
}
final class Immutable extends Base { //final to avoid being extended and then implement the setters
}
这就是我能做的一点点吗?但是为什么需要这样的场景呢?
【讨论】:
final 类 Foo 可以“保证”Foo 的实例不会真正成为某些邪恶的可变派生 Foo 的实例,但有时它拥有一个指定为不可变的可继承甚至抽象的类可能会有所帮助(这意味着任何可变的派生类都将被视为“损坏”)。例如,在某些情况下,定义一个ImmutableMatrix 抽象类可能很有用,其派生类包括ImmutableArrayMatrix(由与矩阵大小相同的数组支持)、ImmutableConstantMatrix(由...
ImmutableMergedMatrix(它将包含对两个或多个 ImmutableMatrix 实例的引用,并且,对于每个,一些整数定义应该应用于最终矩阵的该矩阵的部分)等。如果特定应用程序将使用其内容符合某些与任何预先存在的实现不匹配的模式的矩阵,它可能是有用的能够定义一个新类。可以肯定的是,违反不变性的派生类会破坏事物,但是错误...
另一种选择是使用与UnmodifiableList 相同的策略。首先,创建一个指定类型的接口。
interface List<T>{
List<T> add(T t);
T getAt(int i);
...
}
然后你用所有的业务逻辑实现你的可变类:
public class MutableList<T> implements List<T>{
@Override
List<T> add(T t){ ... }
@Override
T getAt(int i){ ... }
...
}
最后,创建不可变类作为可变类的视图。您实现了相同的接口,但将所有读取方法调用委托给查看的对象,并通过异常禁止任何写入访问。
public class UnmodifiableList<T> implements List<T>{
//This guy will do all hard work
private List delegate;
public UnmodifiableList(List<? extends T> delegate){
this.delegate = delegate;
}
//Forbidden mutable operation: throw exception!
@Override
List<T> add(T t){
throw new UnsupportedOperationException("List is unmodifiable!");
}
//Allowed read operation: delegate
@Override
T getAt(int i){
return delegate.getAt(i);
}
...
}
这种方法的好处是您只需实现一次业务逻辑,并且可以先使用自己的方法和验证检查构建一个对象,然后再将其转换为不可变对象。
【讨论】: