Domanda

Interfacce consentono di creare codice che definisce i metodi delle classi che lo implementano.Non è tuttavia possibile aggiungere alcun codice a questi metodi.

Classi astratte ti permettono di fare la stessa cosa, oltre ad aggiungere codice al metodo.

Ora, se è possibile raggiungere lo stesso obiettivo con le classi astratte, perché abbiamo bisogno del concetto di interfacce?

Mi è stato detto che ha a che fare con la teoria OO da C++ a Java, che è ciò su cui si basa il materiale OO di PHP.Il concetto è utile in Java ma non in PHP?È solo un modo per evitare di avere segnaposto disseminati nella classe astratta?Mi sto perdendo qualcosa?

È stato utile?

Soluzione

Lo scopo principale delle interfacce è darti la flessibilità necessaria per costringere la tua classe a implementare più interfacce, ma non consentire comunque l'ereditarietà multipla.I problemi con l'ereditarietà da più classi sono molti e vari e il file Wikipedia la pagina li riassume abbastanza bene.

Le interfacce sono un compromesso.La maggior parte dei problemi con l'ereditarietà multipla non si applica alle classi base astratte, quindi la maggior parte dei linguaggi moderni al giorno d'oggi disabilita l'ereditarietà multipla ma chiama interfacce di classi base astratte e consente a una classe di "implementare" quante ne desidera.

Altri suggerimenti

Il concetto è utile ovunque nella programmazione orientata agli oggetti.Per me penso all'interfaccia come a un contratto.Finché la mia classe e la tua classe concordano su questo contratto di firma del metodo che possiamo "interfacciare".Per quanto riguarda le classi astratte, quelle che vedo sono più classi di base che eliminano alcuni metodi e devo inserire i dettagli.

Perché avresti bisogno di un'interfaccia, se ci sono già classi astratte?Per prevenire l'ereditarietà multipla (può causare più problemi noti).

Uno di questi problemi:

Il "problema dei diamanti" (a volte indicato come il "diamante mortale della morte") è un'ambiguità che si presenta quando due classi B e C ereditano da A e Classe D eredita da B e C.Se esiste un metodo in A che B e C hanno sovrascritto e D non lo sovrascrive, allora quale versione del metodo eredita D:quello di B, o quello di C?

Fonte: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

Perché/Quando utilizzare un'interfaccia?Un esempio...Tutte le auto nel mondo hanno la stessa interfaccia (metodi)... AccelerationPedalIsOnTheRight(), BrakePedalISOnTheLeft().Immagina che ogni marca automobilistica abbia questi "metodi" diversi da un'altra marca.La BMW avrebbe i freni sul lato destro e la Honda avrebbe i freni sul lato sinistro della ruota.Le persone dovrebbero imparare come funzionano questi "metodi" ogni volta che acquistano una marca diversa di auto.Ecco perché è una buona idea avere la stessa interfaccia in più "luoghi".

Cosa fa per te un'interfaccia (perché qualcuno dovrebbe usarne una)?Un'interfaccia ti impedisce di commettere "errori" (ti assicura che tutte le classi che implementano un'interfaccia specifica avranno tutte i metodi presenti nell'interfaccia).

// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{   
    public function Create($personObject);
}

class MySqlPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Create a new person in MySql database.
    }
}

class MongoPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
    }
}

In questo modo, il Create() il metodo verrà utilizzato sempre allo stesso modo.Non importa se stiamo usando il file MySqlPerson classe o il MongoPerson classe.Il modo in cui utilizziamo un metodo rimane lo stesso (l'interfaccia rimane la stessa).

Ad esempio, verrà utilizzato in questo modo (ovunque nel nostro codice):

new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);

In questo modo, qualcosa del genere non può accadere:

new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);

È molto più facile ricordare un'interfaccia e utilizzare la stessa ovunque, piuttosto che molteplici interfacce diverse.

In questo modo, l'interno del Create() può essere diverso per classi diverse, senza influenzare il codice "esterno", che chiama questo metodo.Tutto ciò che il codice esterno deve sapere è che il metodo Create() ha 1 parametro ($personObject), perché è così che il codice esterno utilizzerà/chiamerà il metodo.Al codice esterno non interessa cosa succede all'interno del metodo;basta saperlo usare/chiamare.

Puoi farlo anche senza interfaccia, ma se usi un'interfaccia, è "più sicuro" (perché ti impedisce di commettere errori).L'interfaccia ti assicura che il metodo Create() avrà la stessa firma (stessi tipi e stesso numero di parametri) in tutte le classi che implementano l'interfaccia.In questo modo puoi essere sicuro che QUALSIASI classe che implementa il file IPersonService interfaccia, avrà il metodo Create() (in questo esempio) e avrà bisogno di solo 1 parametro ($personObject) per essere chiamato/utilizzato.

Una classe che implementa un'interfaccia deve implementare tutti i metodi che l'interfaccia fa/ha.

Spero di non essermi ripetuto troppo.

La differenza tra l'utilizzo di un'interfaccia e di una classe astratta per me ha più a che fare con l'organizzazione del codice, che con l'applicazione da parte del linguaggio stesso.Li uso molto quando preparo il codice con cui altri sviluppatori possono lavorare in modo che rimangano entro i modelli di progettazione previsti.Le interfacce sono una sorta di "progettazione per contratto" in base alla quale il tuo codice accetta di rispondere a una serie prescritta di chiamate API che potrebbero provenire da codice a cui non hai accesso.

Sebbene l'ereditarietà dalla classe astratta sia una relazione "è un", non è sempre ciò che desideri e l'implementazione di un'interfaccia è più una relazione "agisce come una".Questa differenza può essere piuttosto significativa in determinati contesti.

Ad esempio, supponiamo di avere una classe astratta Account da cui si estendono molte altre classi (tipi di account e così via).Ha un particolare insieme di metodi applicabili solo a quel gruppo di tipi.Tuttavia, alcune di queste sottoclassi di account implementano Versionable, Listable o Editable in modo che possano essere inserite nei controller che prevedono di utilizzare tali API.Al controllore non interessa di che tipo di oggetto si tratti

Al contrario, posso anche creare un oggetto che non si estende da Account, ad esempio una classe astratta Utente, e implementare comunque Listable e Editable, ma non Versionable, il che non ha senso in questo caso.

In questo modo, sto dicendo che la sottoclasse FooUser NON è un account, ma si comporta come un oggetto modificabile.Allo stesso modo BarAccount si estende da Account, ma non è una sottoclasse Utente, ma implementa Editable, Listable e anche Versionable.

Aggiungere tutte queste API per Editable, Listable e Versionable nelle classi astratte non solo sarebbe disordinato e brutto, ma duplicherebbe le interfacce comuni in Account e Utente o forzerebbe il mio oggetto Utente a implementare Versionable, probabilmente solo per lanciare un eccezione.

Le interfacce sono essenzialmente un modello per ciò che puoi creare.Definiscono quali metodi una classe deve avere, ma puoi creare metodi aggiuntivi al di fuori di tali limitazioni.

Non sono sicuro di cosa intendi per non poter aggiungere codice ai metodi, perché puoi.Stai applicando l'interfaccia a una classe astratta o alla classe che la estende?

Un metodo nell'interfaccia applicato alla classe astratta dovrà essere implementato in quella classe astratta.Tuttavia, applica quell'interfaccia alla classe di estensione e il metodo deve essere implementato solo nella classe di estensione.Potrei sbagliarmi qui: non utilizzo le interfacce tutte le volte che potrei/dovrei.

Ho sempre pensato alle interfacce come a un modello per sviluppatori esterni o a un set di regole aggiuntivo per garantire che le cose siano corrette.

Utilizzerai le interfacce in PHP:

  1. Per nascondere l'implementazione: stabilisci un protocollo di accesso a una classe di oggetti e modifica l'implementazione sottostante senza refactoring in tutti i luoghi in cui hai utilizzato tali oggetti
  2. Per verificare il tipo, ad esempio per assicurarsi che un parametro abbia un tipo specifico $object instanceof MyInterface
  3. Per imporre il controllo dei parametri in fase di esecuzione
  4. Per implementare più comportamenti in una singola classe (creare tipi complessi)

    class Car implements EngineInterface, BodyInterface, SteeringInterface {

in modo che a Car oggetto ca ora start(), stop() (EngineInterface) o goRight(),goLeft() (Interfaccia dello sterzo)

e altre cose a cui non riesco a pensare in questo momento

Il numero 4 è probabilmente il caso d'uso più ovvio che non puoi affrontare con classi astratte.

Dal pensiero in Java:

Un'interfaccia dice: "Questo è come saranno tutte le classi che implementano questa particolare interfaccia". Pertanto, qualsiasi codice che utilizza una particolare interfaccia sa quali metodi possono essere richiesti per quell'interfaccia, e questo è tutto.Quindi l'interfaccia viene utilizzata per stabilire un “protocollo” tra le classi.

Le interfacce esistono non come base su cui le classi possono estendersi ma come mappa delle funzioni richieste.

Quello che segue è un esempio di utilizzo di un'interfaccia in cui una classe astratta non si adatta:
Diciamo che ho un'applicazione di calendario che consente agli utenti di importare dati di calendario da fonti esterne.Scriverei classi per gestire l'importazione di ogni tipo di origine dati (ical, rss, atom, json). Ciascuna di queste classi implementerebbe un'interfaccia comune che garantirebbe che tutte abbiano i metodi pubblici comuni di cui la mia applicazione ha bisogno per ottenere i dati.

<?php

interface ImportableFeed 
{
    public function getEvents();
}

Quindi, quando un utente aggiunge un nuovo feed, posso identificare il tipo di feed a cui si riferisce e utilizzare la classe sviluppata per quel tipo per importare i dati.Ogni classe scritta per importare dati per un feed specifico avrebbe un codice completamente diverso, altrimenti potrebbero esserci pochissime somiglianze tra le classi al di fuori del fatto che sono necessarie per implementare l'interfaccia che consente alla mia applicazione di consumarle.Se dovessi utilizzare una classe astratta, potrei facilmente ignorare il fatto che non ho sovrascritto il metodo getEvents() che interromperebbe la mia applicazione in questa istanza mentre l'utilizzo di un'interfaccia non consentirebbe l'esecuzione della mia app se QUALSIASI dei metodi definiti nell'interfaccia non esistono nella classe che l'ha implementata.Alla mia app non deve interessare quale classe utilizza per ottenere dati da un feed, solo che siano presenti i metodi necessari per ottenere tali dati.

Per fare un ulteriore passo avanti, l'interfaccia si rivela estremamente utile quando torno alla mia app di calendario con l'intento di aggiungere un altro tipo di feed.Usare l'interfaccia ImportableFeed significa che posso continuare ad aggiungere più classi che importano diversi tipi di feed semplicemente aggiungendo nuove classi che implementano questa interfaccia.Ciò mi consente di aggiungere tantissime funzionalità senza dover aggiungere inutilmente volume alla mia applicazione principale poiché la mia applicazione principale si basa solo sulla disponibilità dei metodi pubblici richiesti dall'interfaccia, quindi finché le mie nuove classi di importazione dei feed implementano l'interfaccia ImportableFeed, allora io so che posso semplicemente lasciarlo sul posto e continuare a muovermi.

Questo è solo un inizio molto semplice.Posso quindi creare un'altra interfaccia che può essere richiesta a tutte le mie classi di calendario per implementare che offra più funzionalità specifiche per il tipo di feed gestito dalla classe.Un altro buon esempio potrebbe essere un metodo per verificare il tipo di feed, ecc.

Questo va oltre la domanda, ma poiché ho usato l'esempio sopra:Le interfacce presentano una serie di problemi se utilizzate in questo modo.Mi trovo a dover garantire che l'output restituito dai metodi implementati corrisponda all'interfaccia e per raggiungere questo obiettivo utilizzo un IDE che legge i blocchi PHPDoc e aggiungo il tipo restituito come suggerimento di tipo in un blocco PHPDoc dell'interfaccia che verrà quindi tradurre nella classe concreta che lo implementa.Le mie classi che consumano l'output dei dati dalle classi che implementano questa interfaccia sapranno almeno che si aspetta un array restituito in questo esempio:

<?php
interface ImportableFeed 
{
    /**
     * @return array
     */
    public function getEvents();
}

Non c'è molto spazio per confrontare classi e interfacce astratte.Le interfacce sono semplicemente mappe che, una volta implementate, richiedono che la classe disponga di un insieme di interfacce pubbliche.

Le interfacce non servono solo per assicurarsi che gli sviluppatori implementino determinati metodi.L'idea è che, poiché è garantito che queste classi dispongano di determinati metodi, è possibile utilizzare questi metodi anche se non si conosce il tipo effettivo della classe.Esempio:

interface Readable {
  String read();
}

List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
  System.out.println(reader.read());

In molti casi, non ha senso fornire una classe base, astratta o meno, perché le implementazioni variano notevolmente e non condividono nulla in comune oltre ad alcuni metodi.

I linguaggi tipizzati dinamicamente hanno la nozione di "digitazione duck" in cui non sono necessarie interfacce;sei libero di presumere che l'oggetto abbia il metodo che lo stai chiamando.Questo risolve il problema nei linguaggi tipizzati staticamente in cui il tuo oggetto ha un metodo (nel mio esempio, read()), ma non implementa l'interfaccia.

A mio parere, le interfacce dovrebbero essere preferite rispetto alle classi astratte non funzionali.Non sarei sorpreso se ci fosse anche un calo di prestazioni in questo caso, dato che c'è un solo oggetto istanziato, invece di analizzarne due, combinandoli (anche se, non posso esserne sicuro, non ho familiarità con il funzionamento interno di OOP PHP).

È vero che le interfacce sono meno utili/significative rispetto, ad esempio, a Java.D'altra parte, PHP6 introdurrà ulteriori suggerimenti sul tipo, inclusi suggerimenti sul tipo per i valori restituiti.Ciò dovrebbe aggiungere valore alle interfacce PHP.

tl;dr:interfacce definisce un elenco di metodi che devono essere seguiti (si pensi all'API), mentre una classe astratta fornisce alcune funzionalità di base/comuni, che le sottoclassi perfezionano in base a esigenze specifiche.

Non ricordo se PHP è diverso sotto questo aspetto, ma in Java puoi implementare più interfacce, ma non puoi ereditare più classi astratte.Presumo che PHP funzioni allo stesso modo.

In PHP puoi applicare più interfacce separandole con una virgola (penso di non trovarla una soluzione pulita).

Per quanto riguarda più classi astratte potresti avere più abstract che si estendono a vicenda (di nuovo, non ne sono del tutto sicuro, ma penso di averlo già visto da qualche parte).L'unica cosa che non puoi estendere è una lezione finale.

Le interfacce non forniranno al tuo codice alcun aumento delle prestazioni o qualcosa del genere, ma possono fare molto per renderlo manutenibile.È vero che una classe astratta (o anche una classe non astratta) può essere utilizzata per stabilire un'interfaccia per il tuo codice, ma le interfacce appropriate (quelle che definisci con la parola chiave e che contengono solo le firme dei metodi) sono semplicemente più facili da usare. ordinare e leggere.

Detto questo, tendo ad usare discrezione nel decidere se utilizzare o meno un'interfaccia su una classe.A volte desidero implementazioni di metodi predefiniti o variabili comuni a tutte le sottoclassi.

Naturalmente, anche il punto relativo all'implementazione di più interfacce è valido.Se hai una classe che implementa più interfacce, puoi utilizzare un oggetto di quella classe come tipi diversi nella stessa applicazione.

Il fatto che la tua domanda riguardi PHP, tuttavia, rende le cose un po' più interessanti.La digitazione sulle interfacce non è ancora incredibilmente necessaria in PHP, dove puoi praticamente inserire qualsiasi cosa in qualsiasi metodo, indipendentemente dal suo tipo.È possibile digitare staticamente i parametri del metodo, ma alcuni di essi sono interrotti (String, credo, causa alcuni intoppi).Aggiungi a questo il fatto che non puoi digitare la maggior parte degli altri riferimenti e non ha molto valore provare a forzare la digitazione statica in PHP (a questo punto).E per questo motivo aumenta il valore delle interfacce nel PHP, a questo punto è molto inferiore a quello delle lingue fortemente tipizzate.Hanno il vantaggio della leggibilità, ma poco altro.L'implementazione multipla non è nemmeno vantaggiosa, perché devi comunque dichiarare i metodi e fornire loro corpi all'interno dell'implementatore.

Le interfacce sono come i tuoi geni.

Le lezioni astratte sono come i tuoi veri genitori.

I loro scopi sono ereditari, ma nel caso di classi astratte e interfacce, ciò che viene ereditato è più specifico.

Di seguito sono riportati i punti per l'interfaccia PHP

  1. Viene utilizzato per definire il numero richiesto di metodi nella classe [se si desidera caricare html allora sono richiesti id e nome, quindi in questo caso l'interfaccia include setID e setName].
  2. L'interfaccia forza rigorosamente la classe a includere tutti i metodi definiti in essa.
  3. È possibile definire il metodo solo nell'interfaccia con l'accessibilità pubblica.
  4. Puoi anche estendere l'interfaccia come class.Puoi estendere l'interfaccia in php usando la parola chiave extends.
  5. Estendi più interfacce.
  6. Non è possibile implementare 2 interfacce se entrambe condividono la funzione con lo stesso nome.Genererà un errore.

Codice di esempio:

interface test{
    public function A($i);
    public function B($j = 20);
}

class xyz implements test{
    public function A($a){
        echo "CLASS A Value is ".$a;
    }
    public function B($b){
        echo "CLASS B Value is ".$b;
    }
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);

Abbiamo visto che le classi e le interfacce astratte sono simili in quanto forniscono metodi astratti che devono essere implementati nelle classi figlie.Tuttavia, presentano ancora le seguenti differenze:

1.Le interfacce possono includere metodi e costanti astratti, ma non possono contenere metodi e variabili concreti.

2.Tutti i metodi nell'interfaccia devono essere in formato pubblico Ambito di visibilità.

3. Una classe può implementare più di un'interfaccia, mentre può ereditare da una sola classe astratta.

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

Spero che questo possa aiutare a capire chiunque!

Non conosco altri linguaggi, qual è il concetto di interfaccia lì.Ma per PHP, farò del mio meglio per spiegarlo.Sii paziente e per favore commenta se questo ti ha aiutato.

Un'interfaccia funziona come un "contratto", specificando cosa fa un insieme di sottoclassi, ma non come lo fanno.

La regola

  1. Non è possibile istanziare un'interfaccia.

  2. Non è possibile implementare alcun metodo in un'interfaccia, ad es.contiene solo .signature del metodo ma non dettagli (corpo).

  3. Le interfacce possono contenere metodi e/o costanti, ma nessun attributo.Le costanti di interfaccia hanno le stesse restrizioni delle costanti di classe.I metodi di interfaccia sono implicitamente astratti.

  4. Le interfacce non devono dichiarare costruttori o distruttori, poiché si tratta di dettagli di implementazione a livello di classe.
  5. Tutti i metodi in un'interfaccia devono avere visibilità pubblica.

Ora facciamo un esempio.Supponiamo di avere due giocattoli:uno è un cane e l'altro è un gatto.

Come sappiamo, un cane abbaia e un gatto miagola. Questi due hanno lo stesso metodo di conversazione, ma con funzionalità o implementazione diverse.Supponiamo di dare all'utente un telecomando dotato di un pulsante per parlare.

Quando l'utente preme il pulsante parla, il giocattolo deve parlare, non importa se si tratta di un cane o di un gatto.

Questo è un buon caso per utilizzare un'interfaccia, non una classe astratta perché le implementazioni sono diverse.Perché?Ricordare

Se hai bisogno di supportare le classi figlie aggiungendo qualche metodo non astratto, dovresti usare le classi astratte.Altrimenti, le interfacce sarebbero la tua scelta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top