Smalltalk延迟初始化为方法调用?

时间:2016-03-28 16:25:31

标签: smalltalk

这里有一个小问题,变量没有初始化。这些是等价的吗?

comments
        ^ comments ifNil: [ comments := OrderedCollection new ]

-

comments
        ^ comments ifNil: [ self initializeComments ]

initializeComments
    comments := OrderedCollection new

2 个答案:

答案 0 :(得分:2)

让我试着建立这个问题。

延迟初始化

这种技术在节省时间和/或记忆时是有意义的。如果要初始化的对象很大,或者初始化它需要的时间太长,那肯定是有道理的。否则,它没有。

在做出决定时,请考虑以下因素:

时间:对ivar的每次访问都将执行条件语句(ifNil:)。因此,您必须决定在开始时初始化ivar是否更好,然后只需使用它而无需进一步检查。

空间:对象需要一些字节,当然。但是#initializeFoo方法也需要一些字节,因为它是CompiledMethod。例如,如果你写

initialize
  comments ifNil: [self initializeComments].
  ^comments

而不是

initialize
  ^comments ifNil: [comments := OrderedCollection new]

您必须将OrderedCollection的新实例使用的空间与由CompiledMethod对象定义的空间进行比较:

initializeComments
  comments := OrderedCollection new

加上#comments访问者方法中的发送。

此外,惰性初始化技术可防止对ivar的任何直接引用。例如,如果comments是惰性的,则代码将被强制在任何地方使用self comments,BTW会占用额外的空间,因为发送方需要在{{1}的文字框架中使用一个插槽选择器。许多人认为无论如何都应该通过消息访问ivars,但是没有选择仅仅命名ivar也不是一件好事。此外,访问ivar两次的方法,通常最终发送两次getter消息,或者第一次发送它(并且以相同的方法)直接访问ivar(这也不是一个好主意)。例如,

#comments

在这两种情况下,第一行都会发送消息以确保ivar已初始化。第二行有两个选项:它再次发送消息(这是不必要的)或使用ivar,因为程序员知道上面已经初始化了ivar。第二种选择容易出错。例如,存在以下错误的风险:

addComment: aString
    (self comments includes: aString) ifTrue: [^self].
    self comments add: aString

addComment: aString
    (self comments includes: aString) ifTrue: [^self].
    comments add: aString

在决定早期与懒惰初始化时,我也会考虑第三种选择。例如,可以在另一个方法中内联初始化。例如,考虑

addComment: aString
  (self acceptsDuplications not and: [self comments includes: aString])
    ifTrue: [^self].
  comments add: aString

如果没有必要,不需要初始化ivar。

延迟初始化还有另一个副作用。例如,假设客户说

commentsDo: aBlock
  comments isNil ifTrue: [^self].
  comments do: [:c | aBlock value: c]

其中 <receiver> comments isEmpty ifTrue: [^self nothingToDo]. 是拥有<receiver> ivar的对象。此客户端代码可能会产生无意义初始化ivar的副作用。当然,客户不应该这样做。相反,comments应该实现<receiver>服务,但这些是在使用LI技术填充代码之前要考虑的事项。

答案 1 :(得分:1)

必须在comments方法中返回initializeComments变量,否则comments getter方法将在未初始化变量的情况下为第二个变量返回self

我不想在initializeComments中返回任何内容,所以我使用了:

comments
    ^ comments ifNil: [ self initializeComments. comments ]

或者:

comments
    comments ifNil: [ self initializeComments ]. 
    ^ comments

谢谢Mike!

<强> PS。有关更详细的说明,请参阅下面的@LeandroCaniglia答案。