Mi mancano ancora anni per comprendere appieno la distinzione tra una classe astratta e un'interfaccia. Ogni volta che penso di avere un'idea dei concetti di base, vado a cercare stackexchange e faccio due passi indietro. Ma alcuni pensieri sull'argomento e sulla domanda dei PO:
Primo:
Esistono due spiegazioni comuni di un'interfaccia:
Un'interfaccia è un elenco di metodi e proprietà che qualsiasi classe può implementare e, implementando un'interfaccia, una classe garantisce che quei metodi (e le loro firme) e quelle proprietà (e i loro tipi) saranno disponibili quando "si interfaccia" con quella classe o un oggetto di quella classe. Un'interfaccia è un contratto.
Le interfacce sono classi astratte che non possono / non possono fare nulla. Sono utili perché puoi implementarne più di uno, a differenza di quelle classi genitoriali. Ad esempio, potrei essere un oggetto della classe BananaBread ed ereditare da BaseBread, ma ciò non significa che non sia possibile implementare anche le interfacce IWithNuts e ITastesYummy. Potrei persino implementare l'interfaccia IDoesTheDishes, perché non sono solo pane, sai?
Esistono due spiegazioni comuni di una classe astratta:
Una classe astratta è, sai, la cosa non è ciò che la cosa può fare. È come, l'essenza, non proprio una cosa reale. Aspetta, questo ti aiuterà. Una barca è una classe astratta, ma un sexy Playboy Yacht sarebbe una sottoclasse di BaseBoat.
Ho letto un libro su lezioni astratte e forse dovresti leggere quel libro, perché probabilmente non lo capisci e lo sbaglierai se non lo hai letto.
A proposito, il libro Citers sembra sempre impressionante, anche se me ne vado ancora confuso.
Secondo:
Su SO, qualcuno ha posto una versione più semplice di questa domanda, la classica, "perché usare le interfacce? Qual è la differenza? Cosa mi manca?" E una risposta ha usato un pilota dell'aeronautica come semplice esempio. Non è riuscito, ma ha suscitato alcuni grandi commenti, uno dei quali ha menzionato l'interfaccia IFlyable con metodi come takeOff, pilotEject, ecc. E questo mi ha davvero cliccato come un esempio reale del perché le interfacce non sono solo utili, ma cruciale. Un'interfaccia rende un oggetto / classe intuitivo, o almeno dà il senso che lo sia. Un'interfaccia non è a beneficio dell'oggetto o dei dati, ma per qualcosa che deve interagire con quell'oggetto. Il classico frutto-> mela-> fuji o forma-> triangolo-> Esempi equilaterali di ereditarietà sono un ottimo modello per comprendere tassonomicamente un determinato oggetto in base ai suoi discendenti. Informa il consumatore e i processori sulle sue qualità generali, i comportamenti, se l'oggetto è un gruppo di cose, mancherà il tuo sistema se lo metti nel posto sbagliato, o descrivi i dati sensoriali, un connettore in un archivio dati specifico, o dati finanziari necessari per rendere il libro paga.
Un oggetto Plane specifico può avere o meno un metodo per un atterraggio di emergenza, ma sarò incazzato se assumo la sua EmergencyLand come ogni altro oggetto volante solo per svegliarmi coperto in DumbPlane e imparare che gli sviluppatori sono andati con quickLand perché pensavano che fosse tutto uguale. Proprio come sarei frustrato se ogni produttore di viti avesse la propria interpretazione di righty tighty o se la mia TV non avesse il pulsante di aumento del volume sopra il pulsante di riduzione del volume.
Le classi astratte sono il modello che stabilisce ciò che qualsiasi oggetto discendente deve avere per qualificarsi come quella classe. Se non hai tutte le qualità di un'anatra, non importa che tu abbia implementato l'interfaccia IQuack, sei solo uno strano pinguino. Le interfacce sono le cose che hanno senso anche quando non puoi essere sicuro di nient'altro. Jeff Goldblum e Starbuck erano entrambi in grado di pilotare astronavi aliene perché l'interfaccia era affidabile in modo affidabile.
Terzo:
Sono d'accordo con il tuo collega, perché a volte è necessario applicare determinati metodi all'inizio. Se stai creando un record ORM attivo, è necessario un metodo di salvataggio. Questo non dipende dalla sottoclasse che può essere istanziata. E se l'interfaccia ICRUD è abbastanza portatile da non essere accoppiata esclusivamente all'unica classe astratta, può essere implementata da altre classi per renderle affidabili e intuitive per chiunque abbia già familiarità con una delle classi discendenti di quella classe astratta.
D'altra parte, c'era un ottimo esempio prima di quando non saltare a legare un'interfaccia alla classe astratta, perché non tutti i tipi di elenco implementeranno (o dovrebbero) un'interfaccia di coda. Hai detto che questo scenario si verifica metà del tempo, il che significa che tu e il tuo collega avete entrambi torto nella metà del tempo, e quindi la cosa migliore da fare è discutere, discutere, considerare e se si rivelano giusti, riconoscere e accettare l'accoppiamento . Ma non diventare uno sviluppatore che segue una filosofia anche quando non è la migliore per il lavoro da svolgere.