L’utile costruttore

PL\SQL è un linguaggio procedurale ma è possibile adottare uno stile di scrittura orientato alla programmazione ad oggetti.

In un package PL\SQL è frequente dover definire un modello dati in memoria a supporto degli algoritmi di elaborazione.
Per far ciò, io personalmente preferisco utilizzare TYPE RECORD definiti all’interno del package stesso invece di TYPE OBJECT, perché ciò rende il package auto consistente.

Dato un TYPE RECORD è possibile definire uno o più RECORD di questo tipo di dato. L’inizializzazione di queste variabili può essere effettuati in punti diversi del codice nei modi più diversi, ma non si ha alcuna garanzia che il record venga inizializzato sempre in modo completo e corretto.
Questo rischio aumenta quando è necessario estendere il TYPE RECORD aggiungendo un attributo per esempio.
Il rischio è che, le procedure che utilizzano tali RECORD, risentano della inizializzazione incoerente di questi e che ciò produca errori a run-time.

Il concetto di costruttore è una soluzione efficace a questo problema: quando si usa una struttura dati, prima di usarla, è necessario avere garanzia che essa sia stata correttamente inizializzata.

Nel nostro caso l’idea è di considerare un TYPE RECORD l’equivalente di una CLASS e definire una FUNCTION che svolga il ruolo di costruttore.
Il costruttore accetta in ingresso tutta una serie di parametri che consentono di inizializzare il RECORD e restituisce il RECORD stesso.
La regola non scritta, si parla appunto di stile di programmazione, è che prima di usare RECORD di questo tipo si invoca sempre il suo costruttore.

SUBTYPE tItemId IS VARCHAR2(50);
SUBTYPE tCurrency IS NUMBER;

TYPE tItem IS RECORD(
   id     tItemId
  ,descr  VARCHAR2(255)
  ,price  tCurrency
  ,qty    NUMBER
  ,total  tCurrency
);
FUNCTION itemNew RETURN tItem IS
  this tItem :=NULL;
BEGIN
  this.qty   := 0;
  this.total := 0;
  RETURN this;
END;

FUNCTION itemNew(
   id IN tItemId
  ,descr IN VARCHAR2
  ,price  tCurrency
  ,qty    NUMBER
) RETURN tItem IS
  this tItem :=itemNew();
BEGIN
  this.id := id;
  this.descr := descr;
  this.price := price;
  this.qty := qty;
  RETURN this;
END;
DECLARE
  item tItem := itemNew();
BEGIN
  item := itemNew(id=>'ID123',descr=>'HAMMER',price=>1.3,qty=>2);
END;

Questo approccio può sembrare costoso a prima vista ma in realtà è semplice e facilmente ripetibile.

Il suo utilizzo rende il codice facilmente comprensibile.
Inoltre nel caso in cui si debba estendere il il TYPE RECORD, alterando il costruttore, avremo garanzia che l’intervento venga effettuato in modo coerente in tutti i punti del codice in cui il costruttore è invocato.

Il consiglio è di predisporre sempre un costruttore base non accetta alcun parametro e che inizializza tutti gli attributi ad un valore di default: nel gergo dei programmatori C un costruttore VOID.

Naturalmente sfruttando l’OVERLOADING è possibile definire una famiglia di costruttori che espongono parametri diversi in base alle varie esigenze applicative.