Programmazione orientata agli oggetti: comprensione delle interfacce
A questo punto, direi che sono state gettate le basi per comprendere la programmazione orientata agli oggetti.
Nello specifico ho trattato:
E, sì, c’è un dibattito su ciò che costituisce le basi (cioè, alcuni non gettano il polimorfismo nel mix anche se lo faccio). Ma i quattro precedenti dovrebbero fornire una solida base su cui continuare a costruire le tue capacità di programmazione orientata agli oggetti.
Ce ne sono altri, ma non penso che siano così profondi, dettagliati o difficili da capire come alcuni dei concetti sopra menzionati. Poi di nuovo, cose diverse diventano più facili per gli altri.
In ogni caso, i prossimi due argomenti che è importante comprendere sono:
- Interfacce
- Astrazione
Parlerò di ciascuno separatamente, ma assicurati di aver letto prima la serie Fundamentals perché i due argomenti precedenti ti permetteranno di fare affidamento su di essi e trarne vantaggio.
Vago, lo so, ma lasciami spiegare e poi vai da lì.
Capire le interfacce
Di gran lunga, la definizione più comune di un’interfaccia che probabilmente sentirai è che si tratta di un contratto. Questo non è sbagliato, ma penso che lasci molto a desiderare.
Ad esempio, quando pensi ai contratti probabilmente pensi a qualcosa che è molto coinvolto, molto gergo, un processo complicato per ottenere qualcosa firmato, datato, pronto per funzionare e così via.
Ma quando si tratta di interfacce di programmazione, non è proprio così. In effetti, direi che la definizione delle interfacce può semplificare la programmazione e allevia molta burocrazia perché rende le cose molto nere o bianche su ciò che qualcosa dovrebbe implementare.
Una parola sulle "interfacce"
Il nostro settore usa la parola "interfaccia" per due cose:
- Designer e utenti usano il termine interfaccia per descrivere cosa vedono e come interagiscono con l’applicazione. Ciò include cose come pulsanti, menu a discesa e altri elementi che possiamo "toccare".
- I programmatori usano il termine per riferirsi a quali funzioni una sottoclasse deve implementare per aderire a un’interfaccia. Questo è chiamato "programmazione su un’interfaccia".
Quest’ultimo è ciò che verrà discusso in questo articolo. E no, non useremo esempi tipici come la programmazione su un’interfaccia Animal o altro. Invece, vedremo di farlo da campioni di codice effettivi.
Programmazione su un’interfaccia
Definiamo "programmazione su un’interfaccia" come un modo per scrivere codice che implementa le firme delle funzioni definite in detta interfaccia.
Ma cosa sono le firme dei metodi? In poche parole, le firme dei metodi includono:
- il nome del nome della funzione,
- gli argomenti che ci vogliono,
- il modificatore di visibilità
Nel contesto di una classe, la vedrai in questo modo:
<?php
class Cache
{
public function set($key, $value)
{
// method implementation
}
}
Facile, vero?
Nel codice sopra, possiamo vedere che la funzione set accetta una chiave e un valore che verranno utilizzati e la funzione è accessibile da qualsiasi oggetto che ha un riferimento alla classe.
Ma le interfacce possono anche includere questo. C’è un avvertimento, però: le interfacce non hanno l’implementazione del metodo.
Quindi, invece di qualcosa del genere:
<?php
class Cache
{
public function set($key, $value) {
set_transient($key, $value);
}
}
Vedrai questo:
<?php
interface iCache
{
public function set($key, $value);
public function get($key);
public function has($key);
}
Ma ci sono anche un paio di sottigliezze da notare nel codice sopra.
- Questo codice non lo definisce come una classe. Invece, lo chiama un’interfaccia.
- Il nome della classe è preceduto da una ‘i’ per indicare che si tratta di un’interfaccia. Questo non è richiesto; è una convenzione
- Il metodo non ha implementazione. Non ha altro che una firma.
Quando creiamo un’interfaccia, diciamo, come accennato in precedenza, che qualunque classe implementi l’interfaccia definirà i metodi che include.
Quindi, se dovessimo collegare tutto ciò che abbiamo visto sopra, l’implementazione finale sarebbe simile a questa (anche se idealmente lo terremmo in file separati):
<?php
interface iCache {
public function set($key, $value);
public function get($key);
public function has($key);
}
public class SimpleCache implemnents iCache
{
public function set($key, $value)
{
set_transient($key, $value, DAY_IN_SECONDS);
}
public function get($key)
{
if (!$this->has($key))
{
return false;
}
return get_transient($key);
}
public function has($key)
{
return false !== get_transient($key);
}
}
Ed è così che le interfacce e le classi si integrano.
Questo è tutto?
In parole povere, sì. Ma nella mia esperienza, ho scoperto che c’è di più che semplicemente definire i metodi e implementarli.
Spesso è facile definire le classi, quindi definire l’interfaccia, quindi implementare l’interfaccia. Ma questo è completamente indietro. Invece, dobbiamo pensare in modo più strategico al nostro lavoro.
Invece di eseguire il backup in un’interfaccia, che vanifica completamente lo scopo, dobbiamo iniziare in modo ampio in modo che le nostre classi possano specializzarsi in ciò che fanno mentre implementano funzionalità comuni non solo a quella classe ma ad altre classi che potrebbero aver bisogno della stessa funzionalità.
Usando l’esempio sopra, potremmo avere un SimpleCache un TransientCache o qualche altro tipo di cache. Indipendentemente dal tipo di cache che implementiamo, implementeranno l’interfaccia e la funzionalità sarà lasciata alla classe che implementa l’interfaccia.
Quindi definiamo come potrebbe apparire una cache ad alto livello, ma le classi di implementazione definiranno esattamente come funzionano.
Se sei uno sviluppatore WordPress e stai cercando di imparare a costruire cose sopra l’applicazione usando tecniche pratiche e orientate agli oggetti, allora perché non unirti al sito?