簡體   English   中英

如何在Smalltalk中在運行時向類添加方法?

[英]How can I add methods to a class at runtime in Smalltalk?

我正在為基於XML的Web服務構建Smalltalk API。 XML服務非常規則,而不是手工編寫方法,我想我只是覆蓋#doesNotUnderstand:通過MyApi class>>compile:動態添加方法MyApi class>>compile: ,然后在工作區中調用所有方法一次,然后刪除DNU並擁有我不錯的API。

這很好用,但將一根巨大的字符串傳遞給#compile:對我來說感覺真的很不對勁; 在Python和其他語言中,我能夠將一個很好的語法檢查的lambda附加到一個類,以更安全的方式實現類似的效果。 例如:

def himaker(name):
    def hello(self, times):
        for x in xrange(times):
            print "Hi, %s!" % name
    return hello
class C(object): pass
C.bob = himaker('Bob')
C.jerry = himaker('Jerry')
a = C()
a.bob(5)

SomeObject>>addHello: name
    | source methodName |
    methodName := 'sayHello', name, 'Times:'.
    source := String streamContents: [ :s |
         s nextPutAll: methodName, ' count'.
         s nextPut: Character cr.
         s nextPut: Character tab.
         s nextPutAll: 'count timesRepeat: [ Transcript show: ''Hi, ', name, '!'' ].' ]
    SomeObject class compile: source

當然必須有像Python版本一樣干凈的東西?

如果您只是希望源字符串更清楚地反映該方法:

SomeObject>>addHello: name
  | methodTemplate methodSource |
  methodTemplate := 'sayHello{1}Times: count
  count timesRepeat: [ Transcript show: ''Hi, {1}!'' ].'.   
  methodSource := methodTemplate format: { name }.
  self class compile: methodSource.

如果您希望對源進行語法檢查,可以從這樣的模板方法開始:

sayHelloTemplate: count
    count timesRepeat: [ Transcript show: 'Hi, NAME' ].

然后相應地填寫模板,例如:

addHello2: name
    | methodTemplate methodSource |
    methodTemplate := (self class compiledMethodAt: #sayHelloTemplate:) decompileWithTemps.
    methodTemplate selector: ('sayHello', name, 'Times:') asSymbol.
    methodSource := methodTemplate sourceText copyReplaceAll: 'NAME' with: name.
    self class compile: methodSource.

當然,如果提取了一些方法,所有這些都會更清楚:)

假設你有模板方法:

SomeClass>>himaker: aName
  Transcript show: 'Hi ...'

然后你可以將它復制到其他類,如果你不想混淆系統瀏覽器,不要忘記設置選擇器和類。 或者,如果您不在乎,只需在方法詞典中安裝副本即可。

| method |

method := (SomeClass>>#himaker:) copy.

method methodClass: OtherClass.
method selector: #boo: .
OtherClass methodDict at: #boo: put: method.

method := method copy.
method selector: #bar: .
method methodClass: OtherClass2.
OtherClass2 methodDict at: #bar: put: method.

好吧,編譯:接受一個字符串。 如果你想要更安全的東西,你可以構建一個parsetree並使用它。

我會用塊:

himaker := [:name | [:n | n timesRepeat: [Transcript show: 'Hi , ', name, '!']]]
hibob = himaker value: 'bob'.
hialice = himaker value: 'alice'.
hialice value: 2

你仍然可以使himaker成為一種方法

himaker: name
    ^[:n | n timesRepeat: [Transcript show: 'Hi, ', name, '!']]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM