малая публичная инициализация - PullRequest
2 голосов
/ 25 апреля 2011

Есть ли способ "скрыть" метод инициализации, чтобы его нельзя было вызвать после создания?

Я бы хотел что-то вроде:

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

Ответы [ 6 ]

1 голос
/ 27 апреля 2011

Вы можете сделать что-то вроде этого:

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

но у вас все еще есть метод инициализации, но теперь он на стороне класса и на самом деле не делает то, что вы хотите. однако .. вы можете попробовать:

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

и на стороне экземпляра:

initializedBy: anInitializationBlock

  anInitializationBlock value: self.

Я думаю, что это дает общее представление о том, что вы хотели. Я не думаю, что это стоит затраченных усилий, так как я могу просто использовать instVarNamed и менять свой объект. Соглашение о малом разговоре простое ... никто из внешних источников не должен вызывать что-либо в вашей категории методов инициализации без действительно хорошего понимания того, почему они это делают.

Вы также можете оставить все это на стороне своего класса 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.
0 голосов
/ 11 мая 2011

методы экземпляра:

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

blockInitialize
    self changeClassTo:(self class subclassWithoutInitialize)

методы класса:

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.
        ].

попробовал по моему (ST / X) образу - работает! Конечно, вспомогательные методы могут быть расположены выше в иерархии ...

0 голосов
/ 26 апреля 2011

Я могу придумать пару разных способов достижения конечной цели,

a) добавить переменную инициализированного экземпляра и пропустить #initialize, если задано значение true,

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

b) добавить тестовый пример, который запускает поиск переписывания в вашем коде и подсчитывает отправителей #initialize, которые не входят в #new метод (ы) его собственной иерархии классов. Фактически, если ваши собственные классы наследуют от общей модели, у вас действительно должен быть только один отправитель #initialize, и это можно легко установить в тестовом примере.

Надеюсь, это поможет.

0 голосов
/ 25 апреля 2011

Вы также не можете реализовать #initialize и все, что вы хотели поместить туда, но не вызывали из #new, вы помещаете в другой метод с другим именем.

0 голосов
/ 25 апреля 2011

IIUC вы спрашиваете, можете ли вы сделать метод частным. Ответ да и нет :) В Smalltalk принято ставить «частные» методы в категорию «частные». Это сигнал внешним пользователям о том, что его не следует использовать, но ничто не мешает им использовать его в любом случае. На практике это работает нормально.

Это то, что вы спрашивали? Если нет, некоторые подробности помогут.

0 голосов
/ 25 апреля 2011

Похоже на работу для Seuss, моей инфраструктуры внедрения зависимостей, которая дает вам большой контроль над процессом инициализации (и, по умолчанию, вызовы initialize, параметры конструкции AFTER передаются в установщики).Это все еще не выпущено, все же.

Чтобы ответить на ваш вопрос, без использования Seuss вы можете перезаписать новый, чтобы он не вызывал initialize:

MyClass>>new
   ^ self basicNew
...