Domanda

Ho iniziato con un'interfaccia generica chiamata ILogin. Le interfacce richiedono l'implementazione di due proprietà: UserID e Password. Ho molte classi di tipo login che implementano questa interfaccia. Man mano che il mio progetto cresceva, scoprii che molte classi ripetevano il codice UserID e la password. Ora decido che ho bisogno di una classe di accesso di base.

È corretto creare una classe Login di base astratta che implementa l'interfaccia ILogin e che tutte le mie classi concrete ereditino solo la classe astratta e la sovrascrivano quando necessario? Inizialmente pensavo che non ci sarebbero stati problemi con questo. Poi ho iniziato a pensare che ILogin probabilmente non era necessario perché probabilmente sarà implementato solo dalla mia classe astratta.

C'è un vantaggio nel mantenere sia la classe astratta che l'interfaccia?

Grazie!

È stato utile?

Soluzione

Sicuramente. Pensiamo a un esempio concreto.

Supponiamo che abbiamo una classe astratta Animal . Supponiamo di creare alcune sottoclassi Cat , Dog , Mosquito e Eagle . Possiamo implementare i suoi metodi Eat () , Breathe () , Sleep () della classe astratta Animal .

Finora tutto bene. Supponiamo ora di avere il metodo Fly () per le classi Mosquito e Eagle . Dato che questi due organismi non sono realmente ben collegati (uno è un uccello, un altro è un insetto) non sarebbe facile trovare un antenato comune per i due che possiamo avere come classe astratta. Questo sarebbe meglio implementato da un'interfaccia IFly .

L'interfaccia IFly può avere un metodo Fly () da implementare. Entrambe le classi Mosquito e Eagle possono essere entrambe sottoclassi della classe astratta Animal e implementare l'interfaccia IFly ed essere in grado su Eat () , Breathe () , Sleep () e Fly () senza alcun tipo di dispari relazione ancestrale tra le due classi.

Altri suggerimenti

Di solito codifico contro classi astratte quando ha senso e implementa (e creo in un assembly / libreria di contratti esterni) un'interfaccia in ogni classe (astratta o no) in modo da poter implementare più facilmente Windows Communication Foundation o inversione di controllo quando necessario (che è quasi sempre per deridere). Questa è diventata una seconda natura per me.

Assolutamente. L'interfaccia è sempre la strada giusta da percorrere - in questo modo qualsiasi cosa può implementarla (incluso qualcosa che ha già un genitore).

La classe astratta tende a farcela in modo da non dover reimplementare alcuni pezzi di quella funzionalità. Swing lo usa un po ', avranno un'interfaccia e quindi un'implementazione predefinita per sovrascrivere solo uno dei 5 metodi o potrebbe occuparsi dell'aggiunta di listener per te, ma non devi usare quella classe base se non voglio.

Se la tua classe astratta è la unica che implementerà mai l'interfaccia, allora puoi sempre controllare solo le istanze della classe astratta, non hai bisogno dell'interfaccia. Ma se vuoi essere compatibile con il futuro con nuove classi non ancora scritte che non estenderanno la classe astratta ma potrebbero usare l'interfaccia, allora continua a utilizzare l'interfaccia ora.

Sono d'accordo con cfeduke. Comincio SEMPRE con le interfacce e in passato ho usato classi astratte che implementano interfacce e forniscono funzionalità di base per promuovere il riutilizzo del codice tra le classi che ereditano dalla classe astratta. Deridere e IOC dipendono generalmente dall'interfaccia, per questo motivo da solo userei le interfacce nei miei progetti.

Se la classe astratta ha funzionalità, è consigliabile conservarla. Ma se contiene solo metodi astratti e nessun campo. Non vedo alcuna utilità nel mantenere entrambi.

Modifica: lavoro sul codice legacy con molte classi astratte. Se mai avrò il tempo, aggiungerò le interfacce (e possibilmente rimuoverò gli abstract vuoti). Perché lavorare con le interfacce migliora notevolmente le possibilità. E onorano il loro nome definendo esattamente l'interfaccia.

La tua interfaccia definisce il contratto che deve essere adempiuto affinché l'oggetto venga accettato; la tua classe astratta definisce il contratto che deve essere adempiuto E definisce alcuni dettagli specifici di implementazione.

Pensaci in questo modo; se pensi che sia mai possibile per chiunque voler adempiere a quel contratto in un modo diverso rispetto al modo in cui la classe astratta abbozza (diciamo, con un'implementazione del tipo di dati di supporto diverso), allora dovresti avere sia l'interfaccia che la classe astratta che lo implementa.

Non c'è quasi nessun overhead nell'avere sia la classe astratta che l'interfaccia; il tuo rischio con questo approccio comporta principalmente un programmatore successivo che si imbatte nell'interfaccia, senza rendersi conto che esiste una classe astratta che implementa l'interfaccia e che crea un'intera implementazione da zero dove non è necessario. Direi che questo potrebbe essere risolto specificando nella documentazione dell'interfaccia che esiste un "predefinito" implementazione dell'interfaccia nella tua classe astratta; mentre alcuni standard di codifica possono disapprovare quella pratica, non vedo alcun problema reale con essa.

Consiglierei sempre di usare le interfacce. Le classi astratte hanno il vantaggio che puoi aggiungere nella funzionalità predefinita, ma richiedere a un utente di utilizzare la propria eredità singola è piuttosto aggressivo.

Le librerie di classi Microsoft favoriscono le classi astratte rispetto alle interfacce in diversi casi perché consentono loro di modificare la classe sottostante. L'aggiunta di un metodo a una classe astratta raramente rompe qualcuno che eredita da essa. L'aggiunta di un metodo a un'interfaccia interrompe sempre i suoi implementatori. Tuttavia, questo fornisce uno dei migliori motivi per utilizzare le interfacce: la terribile possibilità che Microsoft abbia già esaurito la tua unica eredità.

Suggerirei, tuttavia, che nel tuo caso particolare potresti voler rivisitare il modello di disegno che stai utilizzando. Sembra insolito avere un sacco di "tipo di accesso" classi.

Penso che un vantaggio nel mantenere l'interfaccia sarebbe la possibilità per le future classi di implementare interfacce multiple mentre una classe può ereditare solo da una classe astratta.

È possibile estendere la funzionalità delle sottoclassi creando una nuova interfaccia con un diverso set di metodi.

Supponendo che tu stia chiedendo specificamente quando l'interfaccia e la classe astratta hanno firme identiche ...

... (Se i membri dell'interfaccia sono in qualche modo diversi dai membri della classe astratta, ovviamente la risposta è sì, potrebbe essere necessario per entrambi)

... ma supponendo che i membri siano identici, l'unica ragione per cui riesco a pensare di aver bisogno di entrambi è se stai codificando in un sistema che non consente l'ereditarietà multipla di implementazione ci sono due classi nel tuo sistema che devono essere polimorficamente simile, ma deve ereditare da diverse classi base ...

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