Domanda

In java, c'è sempre un caso per permettere a un non-classe astratta per essere esteso?

Sembra sempre di indicare il codice cattivo quando ci sono gerarchie di classe.Lei è d'accordo, e, perché no?

È stato utile?

Soluzione

Sono d'accordo con Jon e Kent, ma, come Scott Myers (in Effective C ++), vado molto più in là. Credo che ogni classe dovrebbe essere o abstract, o final . Cioè, solo le classi foglia in alcuna gerarchia sono davvero adatti per esemplificazione diretta. Tutte le altre classi (cioè nodi interni allo eredità) sono “finito” e dovrebbe pertanto essere <=>.

E 'semplicemente non ha senso per categorie convenzionali per essere ulteriormente estesi. Se un aspetto della classe è utile estendere e / o modificare il modo più pulito sarebbe di prendere quella classe e separarlo in una <=> classe base e una concreta attuazione intercambiabili.

Altri suggerimenti

Ci sono certamente momenti in cui ha senso avere classi concrete non definitive. Tuttavia, sono d'accordo con Kent - Credo che le classi devono essere definitiva (sigillato in C #) per impostazione predefinita, e che i metodi Java dovrebbe essere definitivo per default (come sono in C #)

.

Come dice Kent, eredità richiede attenta progettazione e la documentazione - è molto facile pensare che si può semplicemente ignorare un unico metodo, ma non conoscere le situazioni in cui tale metodo può essere chiamato dalla classe base come parte del resto del implementazione.

"Come si fa a progettare una classe per eredità" per più discussione su questo.

Questa domanda è ugualmente applicabile ad altre piattaforme come C # .NET. Ci sono quelli (me compreso) che ritengono tipi dovrebbero essere definitiva / sigillato per impostazione predefinita e devono essere esplicitamente non sigillata per consentire l'ereditarietà.

Extension tramite ereditarietà è qualcosa che ha bisogno di attenta progettazione e non è così semplice come solo lasciando un tipo non sigillata. Pertanto, penso che dovrebbe essere una decisione esplicita per consentire l'ereditarietà.

C'è un buon ragioni per mantenere il codice non-finale. molti framework come sospensione, molla, guice dipendono sia rami finali che si estende dinamicamente in fase di esecuzione.

per esempio, ibernazione usa le procure per pigro recupero associazione. soprattutto quando si tratta di AOP, si vuole il vostro classi non-finale, in modo che gli intercettori possono allegare ad esso. si veda anche la domanda a SO

Il tuo miglior riferimento è Il punto 15 del eccellente libro di Joshua Bloch "Effective Java", denominata "Design e documento per eredità o altro proibirlo". Tuttavia la chiave se l'estensione di una classe dovrebbe essere consentito non è "cos'è astratto", ma "era stato progettato con in mente l'eredità". V'è talvolta una correlazione tra i due, ma è il secondo che è importante. Per fare un semplice esempio la maggior parte delle classi AWT sono progettati per essere esteso, anche quelli che non sono astratte.

La sintesi del capitolo di Bloch è che l'interazione di classi ereditate con i loro genitori può essere sorprendente e imprevedibile, se l'antenato non è stato progettato per essere ereditato da. Le classi dovrebbero quindi venire in due classi progettate per essere esteso, e con una documentazione sufficiente tipi a) per descrivere come dovrebbe essere fatto b) le classi contrassegnate finale. Le classi in (a) saranno spesso astratta, ma non sempre. Per

In alcuni casi si vuole fare in modo non c'è sottoclassi, in altri casi si vuole garantire la creazione di sottoclassi (abstract). Ma c'è sempre una grande sottoinsieme di classi in cui voi come l'autore originale non si cura e non dovrebbe importare. E 'parte di essere aperto / chiuso. Decidere che qualcosa deve essere chiusa è anche per essere fatto per un motivo.

Non sono d'accordo. Se le gerarchie erano male, non ci sarebbe alcun motivo per esistere linguaggi orientati agli oggetti. Se si guarda al di widget UI librerie di Microsoft e Sun, siete certi di trovare eredità. È tutto "codice cattivo" per definizione? No, certo che no.

L'ereditarietà può essere abusato, ma così può qualsiasi caratteristica del linguaggio. Il trucco è quello di imparare a fare le cose in modo appropriato.

Non potevo essere più in disaccordo.Classe gerarchie di senso per classi concrete quando le classi concrete a conoscenza di un possibile ritorno tipi di metodi che non hanno segnato in finale.Per esempio, una classe di calcestruzzo può avere una sottoclasse gancio:

protected SomeType doSomething() {
return null;
}

Questo doSomething è garantita per essere null o un SomeType istanza.Dire che hanno la capacità di elaborare i SomeType istanza, ma non di un caso d'uso per l'utilizzo del SomeType istanza della classe corrente, ma so che questa funzionalità sarebbe davvero bello avere in sottoclassi e la maggior parte di tutto ciò che è concreto.Non ha senso rendere l'attuale classe una classe astratta se può essere utilizzato direttamente con il difetto di non fare nulla con il suo valore null.Se si ha una classe astratta, quindi si avrebbe i suoi figli in questo tipo di gerarchia:

  • Classe di base astratta
    • Di Default della classe (la classe che avrebbe potuto essere non astratta, solo implementa il metodo protetto e nient'altro)
    • Altre sottoclassi.

Avete quindi una classe base astratta che non può essere utilizzato direttamente, quando la classe predefinita può essere il caso più comune.Nell'altra gerarchia, c'è un meno di classe, in modo che la funzionalità può essere utilizzata senza fare sostanzialmente inutile classe predefinita perché astrazione dovuto essere costretti a prendere la classe.

  • Classe predefinita
    • Altre sottoclassi.

Ora, certo, gerarchie può essere usato e abusato, e se le cose non sono documentato in modo chiaro o classi non ben progettato, le sottoclassi possono incorrere in problemi.Ma questi stessi problemi sono classi astratte così, non si sbarazzarsi del problema solo perché si aggiunge "abstract" alla classe.Per esempio, se il contratto di "doSomething()" metodo di cui sopra richiesto SomeType hanno popolato x, y e z i campi, quando si accedeva tramite i getter e i setter, la sottoclasse sarebbe saltare in aria, a prescindere se si è utilizzato la classe concreta che ha restituito null come base di classe o di una classe astratta.

La regola generale per la progettazione di una gerarchia di classi è praticamente un semplice questionario:

  1. Ho bisogno il comportamento della mia proposta superclasse nel mio sottoclasse?(Y/N) Questa è la prima domanda che è necessario porsi.Se non avete bisogno di un comportamento, non c'è alcun argomento per la creazione di sottoclassi.

  2. Ho bisogno il mio stato d'proposto superclasse nel mio sottoclasse?(Y/N) Questa è la seconda domanda.Se lo stato si adatta al modello di ciò che è necessario, questo può essere un canidate per la creazione di sottoclassi.

  3. Se la sottoclasse è stato creato dalla proposta superclasse, sarebbe veramente È UNA relazione, o è solo una scorciatoia per ereditare il comportamento e lo stato?Questa è la domanda finale.Se è solo una scorciatoia e non è possibile qualificare la propria proposta sottoclasse "come-un" superclasse, quindi eredità dovrebbe essere evitato.Lo stato e la logica può essere copiato e incollato nella nuova classe con una diversa radice, o la delega può essere utilizzata.

Solo se una classe ha bisogno del comportamento, dello stato e può essere considerato che la sottoclasse È-A(n) istanza della superclasse deve essere considerato eredita dalla superclasse.In caso contrario, le altre opzioni che potrebbe essere più adatto allo scopo, anche se può richiedere un po ' di lavoro davanti, è il pulitore a lungo termine.

Ci sono alcuni casi in cui noi non vogliamo permettere di modificare il comportamento. Per esempio, la classe String, Math.

Non mi piace l'eredità perché c'è sempre un modo migliore per fare la stessa cosa, ma quando si apportano modifiche di manutenzione in un sistema di enorme a volte il modo migliore per risolvere il codice con minime modifiche è quello di estendere una classe un po ' . Sì, è di solito porta a un codice male, ma ad uno funzionante e senza mesi di riscrivere prima. Quindi, dando un addetto alla manutenzione la massima flessibilità di poter gestire è un buon modo per andare.

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