2016-02-04 28 views
2

我有一個類,它基本上是一些數據轉換方法的集合。換句話說,我在我的文件中有一些數據,我使用一些不同的代碼片段將文本數據轉換成我可以輕鬆查詢的內容。緩存所有方法的結果

現在,這些方法經常重複使用其他方法,並且隨着核心數據的變化,我想簡單地緩存每種方法的結果,出於速度的原因。

我不想加入到改變每個方法:

^ methodsCache ifNil: [ methodsCache := "compute" ] 

我想用菲羅反射的力量來完成我的任務,而不觸及太多的代碼。我有

一個想法是,如果我可以運行每種方法之前的一些代碼,我既可以件事返回緩存值或繼續該方法的執行,並緩存它的結果

回答

3

您可以使用Reflectivity框架爲您的方法添加前後meta鏈接。鏈接可以在透明執行之前檢查緩存。

link := MetaLink new 
    metaObject: self; 
    selector: #cachedExecute:; 
    arguments: #(selector); 
    control: #before. 
(MyClass>>#myMethodSelector) ast link: link. 

此代碼將安裝發送#cachedExecute:MyClass對象與參數#myMethodSelector元鏈接。該鏈接安裝在編譯方法的第一個AST節點(該方法選擇器的相同方法選擇器上,但可以在另一個方法上)。消息#control:確保鏈接將在AST節點執行之前執行。

你當然可以安裝多個互相影響的元鏈接。

注意,在上面的例子中,你不得再次發送相同的消息(#myMethodSelector)的#cachedExecute:方法裏面,因爲你會在一個循環結束了。

更新 上面的代碼中存在實際的錯誤(現在已修復)。消息#arguments:採用定義通過#selector:指定的方法參數的符號列表。從上下文中將這些參數實際化爲。要傳遞方法選擇器,請使用#selector實例,方法上下文爲#context實例,方法參數爲#arguments。要查看哪些修改可用,請查看RFReification的子類的類側的#key

+0

謝謝最大,這是一個非常好的例子。你有什麼想法我也可以重定向方法的參數? – Uko

+0

另一個問題是我如何執行'cachedExecute:'?我可以調用我的方法的「乾淨」版本嗎?我可以返回一些值而不是運行該方法的其餘部分嗎? – Uko

+0

您可以安裝一個'#after'鏈接,在方法執行被緩存後,在同一個方法*上安裝'#instead'鏈接。然後'#instead'鏈接將返回緩存的值(它將替換整個方法的AST)。 –

0

一個想法,我有是定義

doesNotUnderstand: aMessage 

    aMessage selector beginsWith: 'cached' ifFalse: [^super doesNotUnderstand: aMessage ]. 

    ^cache at: aMessage selector ifAbsentPut: [ 
     self perform: aMessage selector allButFirst: 6 ] 

這樣,你需要做的唯一事情就是更換所有的消息像self methodNameself cachedmethodName發送(或self cachedMethodName但你必須做額外的小寫變通方法doesNotUnderstand:

0

另一個衆所周知的辦法是更換新的,並返回一個緩存代理,委託給實際的對象