Smalltalk如何创建不可变的实例变量?

Smalltalk如何创建不可变的实例变量?,smalltalk,visualworks,gnu-smalltalk,Smalltalk,Visualworks,Gnu Smalltalk,我有一个带有实例变量var的类。 我不希望变量被修改/赋值,除非对象是使用类方法创建的 isImmutable:aBoolean是将可变对象转换为不可变对象的方法,反之亦然。 有人能给我提供正确的语法吗?我还没有试过,但我很确定isImmutable不会起作用。假设它确实使一个对象不可变,它将使instVar指向的对象不可变,而不是instVar本身 最好的办法是根本不包含变量的特定变量,而是在初始化时设置它,如下所示: MyClass class>>newWithFoo: aFoo

我有一个带有实例变量var的类。 我不希望变量被修改/赋值,除非对象是使用类方法创建的

isImmutable:aBoolean是将可变对象转换为不可变对象的方法,反之亦然。
有人能给我提供正确的语法吗?

我还没有试过,但我很确定isImmutable不会起作用。假设它确实使一个对象不可变,它将使instVar指向的对象不可变,而不是instVar本身

最好的办法是根本不包含变量的特定变量,而是在初始化时设置它,如下所示:

MyClass class>>newWithFoo: aFoo
   ^self basicNew initializeWithFoo: aFoo; yourself

MyClass>>initializeWithFoo: aFoo
   self initialize.
   foo := aFoo.
这样,类本身之外的任何人影响变量的唯一方式是通过调用MyClass newWithFoo创建一个新实例:


使用instVarNamed:put之类的反射方法不算在内:-对于它们,您几乎无能为力,但是使用它们的任何人都知道它们正在破坏类的契约。

为什么要使对象不可变?声明API的方式是否足以说明如何使用类而不替换实例变量?

我使用以下代码实现了它:

MyClass class>>classMethod: aValue

anObject := self new value:aValue.
anObject isImmutable: true.
^anObject.

需要记住的一件事是,不变性在对象图的单个级别上运行。实例变量有点像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


您还可以安排将不变性进一步向下传播到对象图中(如果有),但要注意循环。

我通过修改访问器方法实现了它,如下所示:var1:anObject var1:=anObject。自我是可改变的:真的。还有其他更好的方法吗?Stuart Herring我听说修改/实现basicNew不是一个好的面向对象设计实践。如果我错了,请纠正我。我没有建议您修改或实现basicNew,只是您称之为basicNew。我建议的是两种常见的方法之一,即创建一个类端实例创建方法-您通常要么调用new,然后为要设置的值调用public setter,要么调用basicNew并显式调用一个初始化方法,该方法将设置初始值,允许您不为这些变量使用public setter,有效地给了你不变性。我试图学习如何在smalltalk中使用isImmutable。