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

+3


source to share


1 answer


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;

      

+5


source







All Articles