Difference between revisions of "How To Use Interfaces"

From Lazarus wiki
Jump to navigationJump to search
(Category and code highlighting)
 
(14 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Copy the text below and it will demonstrate how to use interfaces to write less code, avoid code repetition,..., this is a fully working program.
+
Copy the text below and it will demonstrate how to use [[Interfaces]] to write less code, avoid code repetition,..., this is a fully working program.
 
+
The default interface in FPC is COM, which makes that once a class with an interface is instantiated as that interface it will automatically be released.
 
+
Note if you change the interface type to CORBA it WILL leak.
<delphi>program interfacesygenerics;
 
  
 +
This example has two unrelated classes, but share the same COM interface.
 +
Since they are instantiated through that interface, destruction is automatic:
 +
<syntaxhighlight lang="pascal">program interfacesygenerics;
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
 
const
 
  STestInterface = '{3FB19775-F5FA-464C-B10C-D8137D742088}';
 
 
 
type
 
type
 
   ITestInterface = interface
 
   ITestInterface = interface
     [STestInterface]
+
     ['{3FB19775-F5FA-464C-B10C-D8137D742088}']
 
     procedure DoSomething;
 
     procedure DoSomething;
 
     procedure DoItAll;
 
     procedure DoItAll;
 
   end;
 
   end;
  
   { Base class Start }
+
   TOneObject = class(TInterfacedObject,ITestInterface)
  TBaseObject = class(TInterfacedObject)
+
     procedure DoSomething;
     procedure DoAll;
+
    procedure DoItAll;
  end;
 
 
 
  procedure TBaseObject.DoAll;
 
  begin
 
    Writeln('TBaseObject DoAll !');
 
 
   end;
 
   end;
  { Base class End }
 
 
type
 
  
   { THook Start}
+
   TOtherObject = class(TInterfacedObject,ITestInterface)
  //Interface implementation on a derived class
 
  THook = class(TBaseObject, ITestInterface)
 
 
     procedure DoSomething;
 
     procedure DoSomething;
    //Contrary to what is stated on the FPC reference manual
+
     procedure DoItAll;
    //it's now possible to use aliases to indicate
 
    //interface implementations
 
     procedure ITestInterface.DoItAll = DoAll;
 
 
   end;
 
   end;
 
+
   procedure THook.DoSomething;
+
   procedure TOneObject.DoSomething;
 
   begin
 
   begin
     Writeln('THook Doing something !');
+
     Writeln('TOneObject DoSomething !');
 
   end;
 
   end;
  { THook End}
 
  
type
+
   procedure TOneObject.DoItAll;
 
+
   begin
  { TRealClass Start }
+
     Writeln('TOneObject DoItAll !');
  TRealClass = class(TBaseObject, ITestInterface)
 
   private
 
    FHook: ITestInterface;
 
   public
 
     constructor Create;
 
    destructor Destroy; override;
 
    //Here we tell the compiler that our class
 
    //interface implementation is provided by
 
    //a member field wich we initialize in this case
 
    //on the constructor
 
    property Hook: ITestInterface read FHook implements ITestInterface;
 
 
   end;
 
   end;
 
+
 
   constructor TRealClass.Create;
+
   procedure TOtherObject.DoSomething;
 
   begin
 
   begin
     //Creating our interface implementor
+
     Writeln('TOtherObect DoSomething !');
    FHook := THook.Create;
 
 
   end;
 
   end;
  
   destructor TRealClass.Destroy;
+
   procedure TOtherObject.DoItAll;
 
   begin
 
   begin
     //Releasing our interface implementor
+
     Writeln('TOtherObect DoItAll !');
    THook(FHook).Free;
 
    inherited Destroy;
 
 
   end;
 
   end;
   { TRealClass End }
+
    
 
 
type
 
    //An example of how to use generics to write
 
    //general use like procedures
 
    //as a bonus they are namespaced by the classname
 
    //disadvantage: can't be overloaded
 
    generic TFakeClass<_GT> = class
 
      class function gmax(a,b: _GT):_GT;
 
    end;
 
 
 
    TFakeClassInt = specialize TFakeClass<integer>;
 
    TFakeClassDouble = specialize TFakeClass<double>;
 
 
 
    class function TFakeClass.gmax(a,b: _GT):_GT;
 
    begin
 
        if a > b then result := a
 
        else result := b;
 
    end;
 
 
 
 
 
 
var
 
var
  R: TRealClass;
+
   I: ITestInterface = nil;
   I: ITestInterface;
 
 
 
 
begin
 
begin
 
   Writeln('Using regular interfaces');
 
   Writeln('Using regular interfaces');
 +
  I := TOneObject.Create as ITestInterface;
 +
  if I <> nil then
 +
    Writeln('Got interface OK. Calling it');
 +
  I.DoSomething;
 +
  I.DoItAll;
 +
  I:=nil;  // releases TOneObject
 +
  I := TOtherObject.Create as ITestInterface;
 +
  if I <> nil then
 +
    Writeln('Got interface OK. Calling it');
 +
  I.DoSomething;
 +
  I.DoItAll;
 +
end.</syntaxhighlight>
 +
== See also ==
  
  R := TRealClass.Create;
+
*[[Accessing the Interfaces directly]]
 
+
*[[Interfaces]]
  //callign the interfaced function directly
+
*[[Understanding Interfaces]]
  R.DoAll;
 
 
 
  //Calling through the interface
 
  if R.GetInterface(STestInterface, I) then
 
    begin
 
      Writeln('Got interface OK. Calling it');
 
      I.DoSomething;
 
      I.DoItAll;
 
    end
 
    else
 
      Writeln('Interface not implemented !');
 
 
 
 
 
    //using the generated generics function
 
    writeln('Integer GMax:', TFakeClassInt.gmax(23,56));
 
    writeln('Double GMax:', TFakeClassDouble.gmax(23.89,56.5));
 
    readln;
 
end.</delphi>
 
  
[[Category:Tutorials]]
+
[[Category:Pascal]]
 +
[[Category:Interfaces]]
 +
[[Category:Example programs]]

Latest revision as of 08:24, 6 October 2021

Copy the text below and it will demonstrate how to use Interfaces to write less code, avoid code repetition,..., this is a fully working program. The default interface in FPC is COM, which makes that once a class with an interface is instantiated as that interface it will automatically be released. Note if you change the interface type to CORBA it WILL leak.

This example has two unrelated classes, but share the same COM interface. Since they are instantiated through that interface, destruction is automatic:

program interfacesygenerics;
{$mode objfpc}{$H+}
type
  ITestInterface = interface
    ['{3FB19775-F5FA-464C-B10C-D8137D742088}']
    procedure DoSomething;
    procedure DoItAll;
  end;

  TOneObject = class(TInterfacedObject,ITestInterface)
    procedure DoSomething;
    procedure DoItAll;
  end;

  TOtherObject = class(TInterfacedObject,ITestInterface)
    procedure DoSomething;
    procedure DoItAll;
  end;
 
  procedure TOneObject.DoSomething;
  begin
    Writeln('TOneObject DoSomething !');
  end;

  procedure TOneObject.DoItAll;
  begin
    Writeln('TOneObject DoItAll !');
  end;
  
  procedure TOtherObject.DoSomething;
  begin
    Writeln('TOtherObect DoSomething !');
  end;

  procedure TOtherObject.DoItAll;
  begin
    Writeln('TOtherObect DoItAll !');
  end;
  
var
  I: ITestInterface = nil;
begin
  Writeln('Using regular interfaces');
  I := TOneObject.Create as ITestInterface;
  if I <> nil then
    Writeln('Got interface OK. Calling it');
  I.DoSomething;
  I.DoItAll;
  I:=nil;  // releases TOneObject
  I := TOtherObject.Create as ITestInterface;
  if I <> nil then
    Writeln('Got interface OK. Calling it');
  I.DoSomething;
  I.DoItAll;
end.

See also