51 OOP 5 – Interfacce

Data la classe madre con all’interno un metodo astratto della lezione precedente:

abstract class figure
{
   private
   $colore = 0x000000,
   $tipoLinea = "solida",
   $spessoreLinea = 1;
 
   abstract public function area();
}

Nella classe figlia rettangolo ho aggiunto le seguenti proprietà e un metodo per assegnare dei numeri casuali ai lati e nel metodo figlio area() il calcolo dell’area con la moltiplicazione dei lati:

class rettangolo extends figure
{
 private
 $lato1= 0, $lato2= 0;
 
 public function __construct()
 {
 $this->lato1 = rand(1,10);
 $this->lato2 = rand(1,10);
 }
 
 public function area()
 {
 return $this->lato1 * $this->lato2;
 }
}

Cosa analoga per la classe cerchio con la relativa formula:

class cerchio extends figure
{
 private
 $raggio=0;
 
 public function __construct()
 {
 $this->raggio = rand(1,5);
 }
 
 public function area()
 {
 return $this-> pow($this->raggio, 2);
 }
}

La funzione pow è una funzione matematica che permette di elevare un numero, il secondo argomento è l’esponente di elevazione (2 corrisponde al quadrato). La formula per calcolare l’area è pi greco * raggio al quadrato.

Creo un array e con un ciclo faccio assegnare ai suoi indici 0 l’oggetto rettangolo o l’oggetto cerchio.

$elencoFigure = array();

for($i=0; $i<10; $i++)
{
 if (rand(1,2) == 1)
  $elencoFigure[$i] = new rettangolo();
 else
  $elencoFigure[$i] = new cerchio();
}

Il meccanismo delle interfacce può sembrare simile a quello astratto, ovvero che la costruzione di certe classi vengano costruite secondo certi canoni o modelli. La differenza è che il principio si applica non solo sull’ereditarietà, ma tra classi anche completamente diverse.

Spesso si ha la necessità di ordinare degli elenchi con dei tipi di dati. Finché si tratta di riordinare dei numeri o al massimo delle stringhe (ordine alfabetico), nessun problema sussiste, ma quando devo ordinare, per esempio, figure maggiori di altre o cliente più importante di un altro o percorso stradale più costoso di un altro. Per ogni caso la logica di ordinamento andrebbe riscritta ogni volta. Una buona procedura è quella di stabilire delle funzioni di ordinamento nelle varie classi.

 usort($elencoFigure, "figure::confronta");

La funzione usort riordina un array definendo una specifica funzione. $elencoFigure è l’array. La classe figure, avrà al suo interno una funzione confronta, che ricevendo in ingresso delle figure determinerà quale sarà quella maggiore. In lavori più grossi un eventuale project potrebbe definire delle interfacce affinchè tutti i programmatori rispettino dei canoni o modelli. Per fare questo dapprima devo definire l’interfaccia con la keyword interface dentro la quale avrò il metodo confronta.

interface Ordinabile
{
 static function confronta($figura1, $figura2);
}

L’interfaccia chiamata Ordinabile ha il metodo statico confronta con 2 parametri (le 2 figure). Ho scelto questi 2 nomi in quanto appropriati, ma visto che l’interfaccia ha la peculiarità di legare oggetti diversi potevo mettere

 interface Ordinabile
{
 static function confronta($oggetto1, $oggetto2);
}

Ho creato un metodo statico per poter segnalare alla funzione di riordino usort il metodo confronta della classe figure, altrimenti avrei dovuto creare un oggetto per poi passargli tale funzione.

 usort($elencoFigure, "figure::confronta");

Bisogna adesso inserire l’interfaccia nella classe madre figure, tramite la keyword implements, affinchè possa essere il metodo confronta possa effettuare azioni specifiche:

abstract class figure implements Ordinabile
{
 private
 $colore = 0x000000,
 $tipoLinea = "solida",
 $spessoreLinea = 1;

 abstract public function area();
 
 public static function confronta($figura1, $figura2)
 {
   if ($figura1->area() == $figura2->area() )
     return 0;
   return $figura1->area() < $figura2->area() ? -1 : 1;
 }
}

creo dentro la classe figure che implementa l’interfaccia Ordinabile, il metodo che inserisce i 2 parametri richiesti dall’interfaccia. Il metodo confronta dice: se la figura 1 è uguale alla due restituisci zero. Altrimenti,  se è minore assegna il valore di confronto -1 , se è maggiore +1. Il punto di domanda (?) è un operatore logico condizionale, cioè interroga in merito al confronto tra le2 figure e gli assegna i 2 valori specificati dopo (- 1 : 1).

Per prova facciamo una stampa del riordino usort delle aree delle figure

$elencoFigure = array();

 for($i=0; $i<10; $i++)
 {
  if (rand(1,2) == 1)
    $elencoFigure[$i] = new rettangolo();
  else
    $elencoFigure[$i] = new cerchio();
 }

usort($elencoFigure, "figure::confronta");

for($i=0; $i<count($elencoFigure); $i++)
  echo $elencoFigure[$i]->area() . io::NL;

Ho ottenuto il mio scopo, ma soprattutto il progettista dovrà fornire agli sviluppatori solo l’informazione di implementare l’ interfaccia (Ordinabile) nelle loro classi. Potrebbero essere anche di più le interfacce da implementare, tipo stampabile, un’implementazione di un’interfaccia di crittografia su dati bancari….. Ricordiamo che l’interfaccia fornisce solo dei vincoli, con una lista di metodi che siamo obbligati a rispettare, la classe astratta, invece, si usa perchè si vuole fornire delle proprietà di base da far ereditare ad altre classi o dei metodi reali.