开发者

smalltalk public initialize

Is there any way to "hide" initialize method so it couldn't be called after construction?

I would like somethi开发者_如何学Pythonng like:

Class>>new: params
  ^super newInstance initializedBy: [
    "actual initialization code"
]


You could do something like this:

Class>>initializeInstance: anInstance
  anInstance instVarNamed: #i put: 1.
  anInstance instVarNamed: #j put: 2.

but, you still have an initialize method of sorts but now it is on the class side and doesn't really do what you want. however.. you could try:

Class>>new: params
  ^super newInstance initializedBy: [ anInstance |
    anInstance instVarNamed: #i put: 1.
    anInstance someMethodCalledOnInitalization.
]

and on the instance side:

initializedBy: anInitializationBlock

  anInitializationBlock value: self.

I think that gets at the general idea of what you wanted. I don't think its worth the effort as I can just reach in using instVarNamed and change your object around. The smalltalk convention is simple... no one from the outside should call anything in your initialization method category w/o a really good understanding of why they are doing it.

You could also keep it all on your class side w:

Class>>new: params
  anInstance := super newInstance.
  ^ self initialize: anInstance using: [ anInstance |
      anInstance instVarNamed: #j put: 1.
  ].

Class>>initialize: anInstance using: aBlock
  aBlock value: anInstance.
  ^ anInstance.


Sounds like a job for Seuss, my dependency injection framework, which gives you a great deal of control over the initialization process (and, by default, calls initialize AFTER construction parameters are passed into setters). It's still unreleased, though.

To answer your question, without using Seuss, you can overwrite new, so that it does not call initialize:

MyClass>>new
   ^ self basicNew


IIUC you're asking if you can make a method private. The answer is yes and no :) The convention in Smalltalk is to put "private" methods in the "private" category. This is a signal to outside users that it's not to be used, but nothing prevents them from actually using it anyway. In practice this seems to work fine.

Is that what you were asking? If not, some more details would help.


You can also NOT implement #initialize and whatever you wanted to put there but not called from #new, you put it in another method with another name.


I can think of a couple of different ways of achieving the end goal,

a) add 'initialized' instance variable and skip #initialize when set to true,

   Contact>>initialize  
     initialized == true ifTrue: [^self].  
     enabled := false.  
     lastModified := Timestamp now.  
     initialized := true.

b) add a test case that runs a rewrite search through your code and counts the senders of #initialize that aren't in the #new method(s) of its own class hierarchy. In fact, if your own classes inherit from a common model, you should really only have one sender of #initialize, and that can be easily asserted in a test case.

Hope this helps.


instance methods:

initialize
    ... do what you need to do ...
    ... then ...
    self blockInitialize

blockInitialize
    self changeClassTo:(self class subclassWithoutInitialize)

class methods:

isSubclassWithoutInitialize
    ^ false

subclassWithoutInitialize
    ^ self subclasses 
        detect:[:cls | cls isSubclassWithoutInitialize]
        ifNone:[
            newClass := self 
                subclass:(self name,'WithoutInitialize')
                instanceVariableNames:''
                classVariableNames:''
                category:'*hidden*'.
            newClass class compile:'isSubclassWithoutInitialize ^ true].
            newClass compile:'initialize ^ self].
            newClass.
        ].

tried it in my (ST/X) image - works! Of course, the helper methods could be placed higher up in the hierarchy...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜