2017-05-30 20 views
3

我已经读过,接口是一个好东西decopule的代码和尼克霍奇斯写了一个很好的篇章。读取我已经产生的代码:德尔福接口和类变量类型

//interfaces 
type 
ILocalization = interface 
    ['{1D144BCE-7D79-4672-8FB5-235422F712EE}'] 
    function localize(const aWordId: string): string; 
end; 

type 
IActions = interface 
    ['{31E8B24F-0B17-41BC-A9E4-F93A8E7F6ECF}'] 
    procedure addWord(const aIndex, aWord: string); 
    procedure removeWord(const aIndex: string); 
end; 

//implementation 
type 
TLocalization = class sealed (TInterfacedObject, ILocalization, IActions) 
    private 
    FTranslationList: TDictionary<string, string>; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    //interface implementations 
    function localize(const aWordId: string): string; 
    procedure addWord(const aIndex, aWord: string); 
    procedure removeWord(const aIndex: string); 
end; 

我打算使用这个类来本地化(翻译)我的delphi android应用程序。


当我打算创建一个类的实例时,我执行以下操作。

var 
Italiano: TLocalization; 
begin 
Italiano := TLocalization.Create; 
end; 

由于TLocalization应该继承AddRef和Release我不会尝试最后这一点,但是这确实发生,即使意大利语是类类型,而不是一个接口类型?

  • 意大利语:

    我的意思,这是TLocalization - >我在这里可以使用所有的方法

  • 意大利语:ILocalization - 在这里>我只能使用本地化功能

考虑到(正如我已经说过的),TLocalization继承了AddRef和Release,如果我理解正确,我不必释放它。它应该与ILocalization一样,但它有其他好处吗?我不明白以上两种情况有什么区别

回答

5
var 
    Italiano: TLocalization; 
begin 
    Italiano := TLocalization.Create; 
    // do stuff 
end; 

这会让你面对混合不同生命周期模型的缺陷。如代码所示,AddRef尚未被调用,因此引用计数为0.因此,您将泄漏此对象。

所以,你可能会改变代码:

var 
    Italiano: TLocalization; 
begin 
    Italiano := TLocalization.Create; 
    try 
    // do stuff 
    finally 
    Italiano.Free; 
    end; 
end; 

现在你不漏。

太好了。但是如果你确实参考了会发生什么?

var 
    Italiano: TLocalization; 
    Localization: ILocalization; 
begin 
    Italiano := TLocalization.Create; 
    try 
    Localization := Italiano as ILocalization; 
    // do stuff 
    finally 
    Italiano.Free; 
    end; 
end; 

现在,当你分配到LocalizationAddRef被调用。因此引用计数变为1.当Localization超出范围时,Release被调用,并且引用计数返回到0并且实例被销毁。不幸的是,你也明确地摧毁它。对象需要被销毁一次。

遵循的最干净和最简单的规则不是混合使用寿命模型。如果您通过引用计数进行生命周期管理,那么只能这样做。确保在创建对象时始终引用对象,并让编译器生成引用计数代码来管理生命周期。

确保遵循该规则的一种方法是确保您只能通过接口引用访问该对象。像这样:

var 
    Italiano: ILocalization; 
begin 
    Italiano := TLocalization.Create; 
    // do stuff 
end; 
+0

好吧我想现在我明白了。所以我们来看看你写的最后一段代码。如果3种方法addWord,removeWord和localize都是在ILocalization里面,我可以完全使用我的课程。但到目前为止,我不能这样做,因为ILocalization只为本地化方法提供了refCount,而不是其他方法,所以我不能调用其他方法。我是否正确? –

+0

否。对象实现了两个接口,而对象拥有引用计数,而不是接口。所以如果你想访问其他方法,使用'var Actions:IActions; ....行动:=意大利语为IActions;'。现在你有两个接口变量,后面是相同的单个对象,现在有一个引用计数为2. –

+0

好吧,所以我可以在终极使用“正常方式”的类,或者我必须做一个类型转换安全使用IActions或ILocalizations。 –