缓存所有方法的结果

Caching the result of all methods

我有一个class,它本质上是一些数据转换方法的集合。换句话说,我的文件中有一些数据,我使用一些不同的代码片段将文本数据转换为我可以轻松查询的内容。

现在这些方法经常相互重用,并且随着核心数据的变化,出于速度原因,我想简单地缓存每个方法的结果。

我不想通过添加来更改每个方法:

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

我想利用 Pharo 反射的强大功能来完成我的任务,而无需接触太多代码。

我的一个想法是,如果我可以在每个方法之前 运行 一些代码,我可以 return 缓存值或继续执行该方法和缓存它的结果

我的一个想法是定义

doesNotUnderstand: aMessage

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

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

通过这种方式,您唯一需要做的就是用 self cachedmethodName(或 self cachedMethodName 替换所有发送的消息,例如 self methodName,但随后您必须在 doesNotUnderstand:)

您可以使用 Reflectivity 框架将 pre 和 post meta link 添加到您的方法中。 link 可以透明地在执行前检查缓存。

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

此代码将安装一个元 link,它使用参数 #myMethodSelector#cachedExecute: 发送到 MyClass 对象。 link 安装在已编译方法的第一个 AST 节点上(属于相同的方法选择器,但可以在另一个方法上)。 #control: 消息确保 link 将在执行 AST 节点之前执行。

您当然可以安装多个相互影响的元link。

请注意,在上面的示例中,您不得#cachedExecute: 方法中再次发送相同的消息 (#myMethodSelector),因为您将结束循环往复。

更新 上面的代码实际上有一个错误(现已修复)。 #arguments: 消息采用符号列表,这些符号定义通过 #selector: 指定的方法的参数。这些参数将从上下文中具体化。要传递方法选择器,您使用 #selector 具体化,方法上下文使用 #context 具体化,方法参数 #arguments。要查看哪些具体化可用,请查看 RFReification.

的子 class 侧 class 侧的 #key

另一个众所周知的选择是替换您的新 return 缓存代理,委托给实际对象