我有一个带有实例变量 var 的类。
我不希望变量被修改/分配给一个值,除非使用 Class 方法创建对象。
isImmutable:aBoolean 是将可变对象转换为不可变对象的方法,反之亦然。
有人可以为我提供正确的语法吗?
我有一个带有实例变量 var 的类。
我不希望变量被修改/分配给一个值,除非使用 Class 方法创建对象。
isImmutable:aBoolean 是将可变对象转换为不可变对象的方法,反之亦然。
有人可以为我提供正确的语法吗?
我使用以下代码实现了它:
MyClass class>>classMethod: aValue
anObject := self new value:aValue.
anObject isImmutable: true.
^anObject.
为什么要使对象不可变?以一种使如何使用类并且不替换实例变量的方式来声明您的 API 还不够吗?
我还没有尝试过,但我很确定 isImmutable 不会成功。假设这确实使对象不可变,它将使instVar指向的对象不可变,而不是 instvar 本身。
您最好的选择是根本不为变量包含特定的 Mutator,而是在初始化时设置它,如下所示:
MyClass class>>newWithFoo: aFoo
^self basicNew initializeWithFoo: aFoo; yourself
MyClass>>initializeWithFoo: aFoo
self initialize.
foo := aFoo.
这样,类本身之外的任何人都可以影响变量的唯一方法是通过调用创建一个新实例MyClass newWithFoo:
(不包括使用反射方法,例如#instVarNamed:put:
- 你几乎无能为力,但任何使用它们的人都知道他们无论如何都违反了类的合同)。
要记住的一件事是,不变性在对象图中的单个级别上运行。实例变量有点像C++中的常量指针,地址不能改变,但内容可以改变。
这是一个小例子:
| a b |
a := Array with: 1.
b := Array with: a.
b beImmutable.
b at: 1 put: nil.
^b
最终会出现 NoModificationError,您不能编写 b 的任何实例/索引变量,因为 b 是不可变的。
但是您可以写入 b 的实例/索引变量指向的对象:
| a b |
a := Array with: 1.
b := Array with: a.
b beImmutable.
a at: 1 put: 2.
^b
会成功,b 现在是 #(#(2)) 而不是 #(#(1))
如果这是您所追求的,您还可以安排将不变性进一步传播到对象图的下方(但要注意循环)。