你所说的是生命周期依赖链,一个东西依赖于另一个东西,而后者可能会在它的控制范围之外被修改。
如果你有一个幂等函数,从 a, b 映射到 c,其中,如果 a 和 b 相同,则 c 相同,但检查 b 的成本很高,那么你可以选择:
1. 接受你有时候使用过时信息并且不总是检查 b。
2. 尽力使检查 b 尽可能快。
你无法两全其美...
如果你可以在顶部添加一个基于 a 的额外缓存,那么这对最初的问题没有任何影响。如果你选择了 1,那么你就拥有了你给自己的自由,并且可以缓存更多内容,但必须记得考虑 b 的缓存值的有效性。如果你选择了 2,则仍然必须每次检查 b,但如果 b 没问题,就可以退而求其次,使用 a 的缓存。
如果你层叠缓存,你必须考虑是否因为组合行为而违反了系统的“规则”。
如果你知道如果 b 有效,a 总是有效的,那么你可以像这样排列缓存(伪代码):
private map<b,map<a,c>> cache
private func realFunction
get(a, b)
{
c result;
map<a,c> endCache;
if (cache[b] expired or not present)
{
remove all b -> * entries in cache;
endCache = new map<a,c>();
add to cache b -> endCache;
}
else
{
endCache = cache[b];
}
if (endCache[a] not present)
{
result = realFunction(a,b);
endCache[a] = result;
}
else
{
result = endCache[a];
}
return result;
}
显然,连续叠加(比如说 x)是微不足道的,只要在每个阶段新添加的输入的有效性匹配 x:b 和 x:a 的 a:b 关系。然而,很可能会出现三个输入其有效性完全独立(或循环),因此不能进行分层。这意味着标记为 // important 的行必须更改为:如果 (endCache[a] 过期或不存在)。