Skip to content

Blog su Lazarus e il Pascal

Scrivi una volta e compila dove vuoi…

Interfacce (Interface) – Parte 4

Posted on 25 Settembre 202325 Settembre 2023 By DragoRosso

Eccoci all’ultimo capitolo sull’argomento (qui il link al precedente articolo: https://blog.lazaruspascal.it/2023/09/25/interfacce-interface-parte-3/)

In questo post costruiremo un programma che sfrutti le unità che abbiamo costruito negli scorsi capitoli.

In sintesi abbiamo implementato varie classi di animali dando a ciascuno delle caratteristiche sui movimenti tipici della specie (es. l’anatra corre, vola e nuota).

Tutto ciò è stato effettuato usando le interfacce per descrivere i movimenti e abbinarle alle singole classi o alle famiglie (i cui derivati ereditano i metodi appunto per ereditarietà).

Come prima cosa andiamo a generare una applicazione nuova (Form1, Unit1) e poi ci aggiungiamo le unità viste in precedenza.

Dopo di che andiamo a immettere nella Form due controlli (RadioGroup e Memo) che chiameremo RG_ElencoTipiAnimali e LogMemo, inoltre aggiungeremo due pulsanti che ci consentiranno di effettuare le operazioni volute.

In particolare in LogMemo verranno visualizzate tutte le messaggistiche.

Il progetto completo si trova in allegato.

Ciò che andremo a documentare è come andare a trovare per la tipologia di animale selezionata (o le famiglie) le proprietà di movimento ed eseguire i metodi delle varie interfacce attribuite alla classe.

Come vedremo, la cosa interessante è che andremo a costruire di volta in volta un riferimento alla singola interfaccia (tramite la classe e non si dovrà però eseguire alcun processo di “free” o distruzione. In effetti potete osservare che in tutto il programma non c’è alcuna esecuzione del “Free”.

Questo perchè le interfacce godono della proprietà di essere automaticamente distrutte nel momento in cui vanno a NIL o con il conteggio dei riferimenti a ZERO.

C’è ovviamente una contropartita a ciò: per mantenere il conteggio dei riferimenti, si aggiungono automaticamente delle chiamate a delle funzioni (Query, Add e Release di cui avevamo accennato nei precedenti Post) e ciò ovviamente ha un impatto sulle prestazioni. L’impatto in un normale programma non è apprezzabile, ma se sono richieste prestazioni importanti questo fatto può incidere in maniera più o meno significativa.

Come dicevo, viene chiamato il costruttore della classe ma come riferimento ad una interfaccia (Animali: IInterface) e non alla classe.

var Animali: IInterface;
Animali := AnimaliClass.Create(...)

Questa cosa fa si l’interfaccia così riferita venga liberata in maniera “automatica” secondo quanto già detto in precedenza.

Ci sono tre blocchi funzionali che consento di effettuare quanto detto come scopo:

1) Andiamo per praticità a costruire un elenco delle classi degli animali (e delle famiglie) implementati.

function TForm1.GetAnimaliClasses(): TArray<TAnimaliClass>;
begin
  Result := TArray<TAnimaliClass>.Create(
    TAnimali,
    TUccelli, TAnatra, TStruzzo, TPinguino,
    TPesci, TArringa, TSalmone, TSqualo,
    TInsetti, TFormica, TFarfalla,
    TMammiferi, TPippistrello, TGatto, TCane, TBalena
  );
end;

2) Cicliamo nell’elenco e tramite le RTTI andiamo a riempire una griglia di “RadioButton” associando a ciascun selettore il nome della classe.

procedure TForm1.FillAnimalTypesButtonClick(Sender: TObject);
var
  AnimaliClass: TAnimaliClass;
  RttiContext: TRttiContext;
  RttiTypes: TArray<TRttiType>;
  RttiType: TRttiType;
begin
  RG_ElencoTipiAnimali.Items.Clear();
  for AnimaliClass in GetAnimaliClasses do
  begin
    Log(AnimaliClass);
    RG_ElencoTipiAnimali.Items.Add(' ' + AnimaliClass.ClassName);
  end;
  RG_ElencoTipiAnimali.ItemIndex := 0;
end;

3) Ora che abbiamo l’elenco, possiamo selezione una classe e sempre tramite le RTTI e le RTL possiamo visualizzare i movimenti possibili (anche i derivati dall’interfaccia di famiglia) ed eseguirli.

procedure TForm1.ShowAnimalLocomotionsButtonClick(Sender: TObject);
var
  AnimaliClassName: string;
  AnimaliClass: TAnimaliClass;
  Animali: IInterface;
  Volare: IVola;
  Saltare: ISalta;
  Correre: ICorre;
  Nuotare: INuota;
begin
  Log('');
  AnimaliClassName := Trim(RG_ElencoTipiAnimali.Items[RG_ElencoTipiAnimali.ItemIndex]);

  Log(Format('Ricerca per il match della classe %s', [AnimaliClassName]));
  for AnimaliClass in GetAnimaliClasses() do
  begin
    if AnimaliClass.ClassNameIs(AnimaliClassName) then
    begin
      Log(Format('Creazione della istanza della classe %s', [AnimaliClassName]));
      //Qui costruiamo il riferimento all'interfaccia della classe !!!
      Animali := AnimaliClass.Create(Self.Log);

      Log(Format('Elenca le interfacce supportate da %s', [AnimaliClassName]));

      if SupportsAndLog(Animali, ISalta, Saltare) then //, TypeInfo(ISalta)) then
        begin
          Log('Esecuzione metodo');
          Saltare.Salta();
        end;

      if SupportsAndLog(Animali, IVola, Volare) then //, TypeInfo(IVola)) then
        begin
          Log('Esecuzione metodo');
          Volare.Vola();
        end;

      if SupportsAndLog(Animali, ICorre, Correre) then //, TypeInfo(ICorre)) then
        begin
          Log('Esecuzione metodo');
          Correre.Corre();
        end;

      if SupportsAndLog(Animali, INuota, Nuotare) then //, TypeInfo(INuota)) then
        begin
          Log('Esecuzione metodo');
          Nuotare.Nuota();
        end;
    end;
  end;
end;

function TForm1.SupportsAndLog(const Instance: IInterface; const IID:TGUID; out Intf; const InterfaceTypeInfo: Pointer = nil): Boolean;
begin
  Result := SupportsAndLog_Works(Instance, Intf, IID, InterfaceTypeInfo);
end;

function TForm1.SupportsAndLog_Works(const Instance: IInterface; out Intf;
    const IID: TGUID; const InterfaceTypeInfo: Pointer = nil): Boolean;
begin
  Result := Supports(Instance, IID, Intf);
end;

Altra ulteriore caratteristica è che non abbiamo usato variabili di alcun tipo nelle classi (ad esempio per distinguere “gli animali”) e anche nel programma abbiamo usato lo stretto indispensabile per definire le istanze.

Qui potete scaricare il progetto completo per Lazarus : https://cloud.dyn-o-saur.com/Test_Interfacce.zip

Se avete suggerimenti o volete fare qualche domanda riguardo questo articolo, potete usufruire del forum italiano su Lazarus e Free Pascal:

https://www.lazaruspascal.it/

Funzioni avanzate Tags:Class, Classi, Interfacce, Interface

Navigazione articoli

Previous Post: Interfacce (Interface) – Parte 3
Next Post: Sviluppare CGI su Apache2 con InstantFpc

Archivi

  • Maggio 2025
  • Aprile 2025
  • Ottobre 2024
  • Maggio 2024
  • Marzo 2024
  • Dicembre 2023
  • Novembre 2023
  • Settembre 2023
  • Giugno 2023
  • Maggio 2023
  • Marzo 2023
  • Maggio 2022
  • Aprile 2022
  • Febbraio 2022
  • Gennaio 2022
  • Dicembre 2021

Categorie

  • Android
  • Funzioni avanzate
  • Installazione alternativa di Lazarus e Free Pascal Compiler (FPC)
  • Installazioni
  • Lazarus ed il Web
  • Lazarus, l'IDE ed i suoi strumenti
  • Sintassi e concetti base
  • Strutture dati
  • Tutorial
Vai al forum Italiano

Articoli recenti

  • Il framework Brook – tutorial 2 – un server CRUD
  • Il framework Brook – tutorial 1 – primi passi
  • Installazione di Lazarus in Linux – Risoluzione problemi
  • Autenticazione 2FA
  • Installazione di Free Pascal e Lazarus su Manjaro Linux

Commenti recenti

  1. DragoRosso su Installazione di Lazarus e Free Pascal – su Linux – tramite package manager a linea di comando

Copyright © 2025 Blog su Lazarus e il Pascal.

Powered by PressBook WordPress theme

Utilizziamo i cookie per essere sicuri che tu possa avere la migliore esperienza sul nostro sito. Se continui ad utilizzare questo sito noi assumiamo che tu ne sia felice.Ok