2016-02-04 29 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

另一个众所周知的办法是更换新的,并返回一个缓存代理,委托给实际的对象