在我们正在开发的Delphi应用程序中,我们有一个相关对象的大结构。这些对象的某些属性具有在运行时计算的值,我正在寻找一种方法来缓存更密集计算的结果。我使用的方法是在第一次计算私有成员时保存值。这是一个简短的例子:
unit Unit1;
interface
type
TMyObject = class
private
FObject1, FObject2: TMyOtherObject;
FMyCalculatedValue: Integer;
function GetMyCalculatedValue: Integer;
public
property MyCalculatedValue: Integer read GetMyCalculatedValue;
end;
implementation
function TMyObject.GetMyCalculatedValue: Integer;
begin
if FMyCalculatedValue = 0 then
begin
FMyCalculatedValue :=
FObject1.OtherCalculatedValue + // This is also calculated
FObject2.OtherValue;
end;
Result := FMyCalculatedValue;
end;
end.
用于计算的对象更改并且应重置和重新计算缓存的值并不罕见。到目前为止,我们通过使用观察者模式解决了这个问题:对象实现OnChange事件,以便其他人可以订阅,在更改和重置缓存值时得到通知。这种方法有效但有一些缺点:
最后一个问题:你能否提出其他方法来实现缓存的计算值?
答案 0 :(得分:4)
如果要避免观察者模式,可以尝试使用散列方法。
这个想法是你'散列'参数,并检查这是否与保存状态的'hash'匹配。如果没有,则重新计算(从而将新哈希保存为密钥)。
我知道我听起来像是在考虑它,但事实上它被知名软件使用。
例如,SCons(Makefile替代)用于检查目标是否需要优先重新构建为时间戳方法。
我们已经使用SCons一年多了,我们从未发现任何未重建的目标问题,因此它们的哈希效果很好!
答案 1 :(得分:2)
您可以存储所需的外部对象值的本地副本。然后,访问例程将本地副本与外部值进行比较,并仅对更改进行重新计算。
访问外部对象属性同样会强制重新评估这些属性,因此系统应自动保持最新状态,但只在需要时重新计算。我不知道你是否需要采取措施来避免循环依赖。
这会增加每个对象所需的空间量,但会删除观察者模式。它还会延迟所有计算,直到需要它们,而不是每次源参数更改时执行计算。我希望这与您的系统相关。
unit Unit1;
interface
type
TMyObject = class
private
FObject1, FObject2: TMyOtherObject;
FObject1Val, FObject2Val: Integer;
FMyCalculatedValue: Integer;
function GetMyCalculatedValue: Integer;
public
property MyCalculatedValue: Integer read GetMyCalculatedValue;
end;
implementation
function TMyObject.GetMyCalculatedValue: Integer;
begin
if (FObject1.OtherCalculatedValue <> FObjectVal1)
or (FObject2.OtherValue <> FObjectVal2) then
begin
FMyCalculatedValue :=
FObject1.OtherCalculatedValue + // This is also calculated
FObject2.OtherValue;
FObjectVal1 := FObject1.OtherCalculatedValue;
FObjectVal2 := Object2.OtherValue;
end;
Result := FMyCalculatedValue;
end;
end.
答案 2 :(得分:1)
在我的工作中,我使用 Bold for Delphi ,可以根据彼此管理无限缓存值的复杂结构。通常每个变量只占问题的一小部分。在此框架中称为派生属性。派生是因为该值未保存在数据库中,它仅取决于数据库中的其他派生属性或持久属性。
这种属性背后的代码在Delphi中作为过程或在模型中的OCL(对象约束语言)中编写。如果你把它写成Delphi代码,你必须订阅依赖变量。因此,如果属性C依赖于A和B,则每当A或B更改用于重新计算的代码时,在读取C时将自动调用。所以第一次读取C和A也被读取(可能来自数据库)。只要A和B没有改变,你就可以阅读C并获得非常快的性能。对于复杂的计算,这可以节省大量的CPU时间。
缺点和坏消息是Bold不再受到官方支持,你也买不到它。我想你可以得到足够的人,但我不知道你可以在哪里下载它。在2005-2006左右,它可以从Borland免费下载,但现在不能再下载了。 它没有为D2009做好准备,因为有人必须将它移植到Unicode。
另一个选项ECO来自Capable Objects的dot.net。 ECO是Visual Studio中的插件。这是一个支持的框架,与Delphi的Bold具有相同的想法和作者。许多事情也得到了改进,例如数据绑定用于GUI组件。 Bold和ECO都使用模型作为具有类,属性和链接的中心点。这些可以保存在数据库或xml文件中。使用免费版ECO,该模型最多可以有12个类,但我记得没有其他限制。
粗体和ECO包含的内容远多于派生属性,这些属性可以提高您的工作效率,让您可以考虑问题而不是数据库的技术细节,或者在您的情况下如何缓存值。欢迎您提出有关这些框架的更多问题!
修改强> 实际上有一个下载link for Embarcadero registred users用于D7的 Bold for Delphi ,很老......我知道有D2005的更新,广告D2006。