Skip to content

Interfaces. An introduction

A last main feature of interfaces must be mentioned: they give us the possibility to bypass another problem that we have always stated as immutable: the multiple inheritance.

It will be the argument for the next programming article.

For now, you can download the whole actual project from here.

Here the code of Employee (remember that Employee is Human, because it inherits this last):

 

unit Employee;

{$mode objfpc}{$H+}

interface

uses
  Classes,SysUtils,Dialogs,
  Human; //Employee IS human (interface)

type
  TEmployee = class(TInterfacedObject, IHuman) //inherits from the Interface !!!

//We have :
//1. Class Attributes (var ...)
//2. Class Methods (constructors, destructor, class static)
//3. Object Attributes (id,name...)
//4. Object Methods (Get,Set...)

  private //PRIVATE ZONE (Only the Class employee can SEE this zone)

    //PRIVATE ATTRIBUTES
    //Id: integer;                                           //Private Object Attribute
    //..

    //PRIVATE METHODS
    //procedure Fake();                                    //Private Object Method
    //...
    class function GetNextFreeId(): integer;               //Private Class Method (class->static in c++)

  protected //PROTECTED ZONE (Only the Class employee and his children can SEE this zone)

    Id: integer;                                           //Protected Object Attribute
    Name: string;                                          //Protected Object Attribute
    Surname: string;                                       //Protected Object Attribute
    Sex : string;

  public   //PUBLIC (Anyone can see this zone)

    //PUBLIC ATTRIBUTES
    //Id_public: integer;                                  //Public Object Attribute (bad NO encapsulation! Object attributes must be private)
    //...

    //PUBLIC METHODS
    //Constructors (Create the object Employee):
    constructor Create(Name_,Surname_,Sex_: string); overload; //Public Class Method
    //The Overload allows you to have different versions of the same named function/procedure with different arguments
    //OVERLOAD : SAME NAME OF FUNCTION WITH DIFFERENT ARGUMENTS IN THE SAME CLASS

    //Destructor (can be only ONE) (Destroy the object Employee)
    Destructor Destroy; virtual;                        //Public Class Method
    //virtual : I want that my children can redaclare this

    class function CountEmployees(): integer;              //Public Class Method (class->static in c++)

    function GetId():integer;                              //Public Object Method
    procedure SetId(Id_:integer);                          //Public Object Method
    function GetName():string;                             //Public Object Method
    procedure SetName(Name_:string);                       //Public Object Method
    function GetSurname():string;                          //Public Object Method
    procedure SetSurname(Surname_:string);                 //Public Object Method
    function PrintMe():string;                             //Public Object Method
    function PrintMeVirtual():string; virtual;   //I want that my children can redaclare this

    //ALL Interface METHODS must be redefined !!!
    function GetSex():string;
    procedure SetSex(Sex_:string);

{
In summary :

OVERLOAD : put it in methods. Redeclare same name of function with different arguments in the same class
VIRTUAL : put in on Fathers method that can be overriden by its children
OVERRIDE : put it on Children method that must redeclare fathers virtual method (Redeclare same name of function with the same arguments in different classes)
INHERITED : put it on Child to invoke (call) fathers method ex : inherited Create(Name_,Surname_)
}

  end;

implementation

uses unit1;

var
  Counter: integer =0;    //Class Attribute SOS !!!

//implementation of the methods here !!!

//Class Method
constructor TEmployee.Create(Name_,Surname_,Sex_: string); overload;
begin
  self.Name:=Name_;
  self.Surname:=Surname_;
  self.Sex := Sex_;

  self.Id := GetNextFreeId();
  counter:=counter+1;

  showmessage('Employee with this info : ' + self.PrintMe() + ' created.');
end;

//Class Method
Destructor TEmployee.Destroy;
begin

  counter:=counter-1;
  showmessage('Employee with Id ' + inttostr(self.Id) + ', Name ' + self.Name + ', Surname ' + self.Surname + ' is deleted');
  //Self->This in c++

  inherited; // Always call the parent destructor after running your own code
end;

//Class Method
class function TEmployee.GetNextFreeId(): integer;
var imax :integer;
begin

  imax := counter-1; //TList start from a[0] etc...
  if imax <> -1 then begin

    result := TEmployee(Form1.EmployeeList.Items[imax]).GetId +1; // (Casting) Last element has the higher id since
                                                                   //i always add elements at the last position
  end else result := 1;

end;

//Class Method
class function TEmployee.CountEmployees(): integer;
begin
  result := counter;
end;

//Object Method
function TEmployee.GetId():integer;
begin
  result := self.Id;
end;

//Object Method
procedure TEmployee.SetId(Id_:integer);
begin
 self.Id := Id_;
end;

//Object Method
function TEmployee.GetName():string;
begin
  result := self.Name;
end;

//Object Method
procedure TEmployee.SetName(Name_:string);
begin
  self.Name := Name_;
end;

//Object Method
function TEmployee.GetSurname():string;
begin
  result := self.Surname;
end;

//Object Method
procedure TEmployee.SetSurname(Surname_:string);
begin
  self.Surname := Surname_;
end;

//Object Method
function TEmployee.PrintMe():string;
var
    semployee :string;
begin

  semployee := 'Id : ' + inttostr(self.Id)  + '; Name : ' + self.Name  + '; Surname : ' + self.Surname + ' with Sex ' + self.Sex + ' ';

  result := semployee + #13#10;

end;

//Object Method
function TEmployee.PrintMeVirtual():string; //virtual NOT NEEDED HERE
var
    semployee :string;
begin

  semployee := '(Virtual print) Id : ' + inttostr(self.Id)  + '; Name : ' + self.Name  + '; Surname : ' + self.Surname + ' with Sex ' +  self.Sex + ' ';

  result := semployee + #13#10;

end;

function TEmployee.GetSex():string;
begin
  result := self.Sex;
end;

procedure TEmployee.SetSex(Sex_:string);
begin
  self.Sex := Sex_;
end;

end.