我有一个带有实例变量var的类 除非使用Class方法创建对象,否则我不希望将变量修改/赋值。
isImmutable:aBoolean是将可变对象转换为不可变对象的方法,反之亦然。
有人可以提供正确的语法吗?
答案 0 :(得分:0)
我没有尝试过,但我很确定isImmutable不会这样做。假设实际上确实使对象不可变,它将使对象指向由instVar不可变,而不是instvar本身。
你最好的选择是根本不要为变量包含一个特定的Mutator,而是在初始化时将其设置为:
MyClass class>>newWithFoo: aFoo
^self basicNew initializeWithFoo: aFoo; yourself
MyClass>>initializeWithFoo: aFoo
self initialize.
foo := aFoo.
这样,类外部的任何人都可以影响变量的唯一方法是通过调用MyClass newWithFoo:
来创建一个新实例
(不计算使用像#instVarNamed:put:
这样的反射方法 - 你几乎无能为力,但任何使用它们的人都知道他们无论如何都违反了合同。)
答案 1 :(得分:0)
为什么要使对象不可变?以一种明确如何使用该类并且不替换实例变量的方式声明您的API是不够的?
答案 2 :(得分:0)
我使用代码实现了它:
MyClass class>>classMethod: aValue
anObject := self new value:aValue.
anObject isImmutable: true.
^anObject.
答案 3 :(得分:0)
要记住的一件事是,不变性在对象图中以单一级别运行。实例变量有点像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))
你也可以安排在对象图中进一步传播不变性,如果你想要的那样(但要注意周期)。