Squeak Smalltalk:初始化不适用于从数组派生的类?



说到Squeak Smalltalk,我有点新手,所以我可能会做错什么,或者对Squeak应该如何工作做出错误的假设。 不过,我还是想知道我哪里出错了...

我试图使类鼓风机派生自Array。 鼓风机基本上是一个数组,但有一个额外的实例变量,称为索引和一些方法。 我以为当我创建一个新对象时,初始化方法会自动运行,并且它会同时初始化数组和索引变量,但这似乎没有发生。 不过,如果我稍后运行"手动"初始化,它会按预期工作。

Array variableSubclass: #Blower
instanceVariableNames: 'index'
(...)
Blower >> initialize
super initialize.
1 to: self size do: [ :ix | self at: ix put: ix ].
self shuffle.
index := 1.

如果我在工作区中执行以下操作: blower := Blower new: 10. blower inspect.

检查窗口显示(不是我预期的): #( nil nil nil nil nil nil nil nil nil nil ) index: nil

如果我手动运行初始化,检查窗口是正确的:

blower initialize.
#( 6 4 1 10 2 8 3 ... )
index: nil

那么,为什么当我创建鼓风机并正确设置它时不初始化运行呢?有没有办法自动化它,让它在创建时发生? 即。开始初始化工作?

看看方法 ArrayedCollection 类>>新的。 它覆盖 new 以调用 new: 作为参数。 这将替换调用初始化的行为中 new 的默认实现。 如果你真的想这样做,实现新的和新的:作为类中的类方法。 在每种情况下,调用 super,然后调用初始化。

new
   ^super new initialize
new: sizeRequested
   ^(super new: sizeRequested) initialize

说了这么多,从 Array 进行子类是一个非常糟糕的主意。 问问自己"在当前使用阵列的任何地方使用鼓风机是否合理? 如果不是,它就不是一个好的子类。 任何时候你从集合类子类,你几乎总是做错了。 你想要的是一个名为Blower的类,它是Object的子类,包含两个实例变量 - 一个用于数组,一个用于索引。 您的类现在将正常初始化。对于要发送到数组的任何操作,请在 Blower 中编写一个方法以将其委托给实例变量。

David Buck 说的是正确的,但还有几件事要补充,特定于 Squeak:

  1. 某些集合调用 #initialize: 而不是在创建实例时 #initialize(例如请参阅哈希集合)

  2. 其他一些可以发送两个 #initialize 然后 #initialize:(请参阅共享队列)

  3. 但是 Array class>>new:有一个完全绕过初始化的特定实现(为了速度起见,已知初始化 Array 不需要任何东西)

正如David所说,对Array进行子类化通常是一个坏主意,看看Squeak,已经有太多的反例了。

最新更新