Delphi interfaces and class variable types
I read that interfaces are a good thing to parse code, and Nick Hodges wrote a good chapter. Reading that I created this code:
//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;
I am planning to use this class to localize (translate) my android delphi apps.
When I am going to make an instance of a class, I do the following.
var
Italiano: TLocalization;
begin
Italiano := TLocalization.Create;
end;
Since TLocalization
AddRef and Release are supposed to inherit, I won't try to do that, but can this happen even if Italiano is a class type and not an interface type?
What I mean:
- Italiano: TLocalization -> here I can use all methods
- Italiano: ILocalization -> here I can only use the localization function
Considering the fact that (as I said) TLocalization inherits AddRef and Release, I don't need to release if I understood correctly. It should be the same with ILocalization, but does it have any other benefits? I don't understand what are the differences in the two cases above
source to share
var
Italiano: TLocalization;
begin
Italiano := TLocalization.Create;
// do stuff
end;
This opens you up to the problems of mixing different life patterns. Since the code is standing, AddRef
it was not called, so the reference count is 0. Therefore, you will miss this object.
This way you can change the code to:
var
Italiano: TLocalization;
begin
Italiano := TLocalization.Create;
try
// do stuff
finally
Italiano.Free;
end;
end;
Now you don't leak.
Great. But what happens if you take the link?
var
Italiano: TLocalization;
Localization: ILocalization;
begin
Italiano := TLocalization.Create;
try
Localization := Italiano as ILocalization;
// do stuff
finally
Italiano.Free;
end;
end;
Now AddRef
called on assignment Localization
. So the reference count goes to 1. When Localization
out of scope, is called Release
and the reference count goes back to 0 and the instance is destroyed. Unfortunately, you also explicitly destroy it. Objects must be destroyed exactly once.
The cleanest and simplest rule to follow is not to mix lifetimes models. If you have reference counting lifecycle management, do so only. Make sure you always refer to the object when you create it and let the compiler generate reference counting code to manage the lifetime.
One way to make sure you follow this rule is to ensure that the object is only accessed through interface references. Like this:
var
Italiano: ILocalization;
begin
Italiano := TLocalization.Create;
// do stuff
end;
source to share