L'ereditarietà gerarchica appartiene al passato? [chiuso]

1

Recentemente ho notato che l'ereditarietà gerarchica può essere una reliquia del pensare alle classi come "strutture con funzioni" piuttosto che a una mentalità legata al contratto di prodotto.

Considerare, come semplice esemplare, l'implementazione di "Iterator non modificabile" da Guava. link È un iteratore che genera un "UnsupportedOperationException" su invocazione di remove ().

Ora, sono sicuro che la maggior parte delle persone sarebbe d'accordo sul fatto che l'implementazione di un contratto e il fatto che uno dei suoi metodi genera sempre un'eccezione è una cattiva forma - quando si implementa un contratto si sta implicitamente garantendo che tutti i metodi funzionino. Eppure, quali sono le nostre opzioni qui? Potremmo dichiarare un'interfaccia che non contiene il metodo remove ma che renderebbe il nostro tipo restituito incompatibile con tutti i metodi che funzionano sugli iteratori. Potremmo incolpare i progettisti dell'API Java per forzare il metodo remove () a far parte di ogni iteratore, piuttosto che spostarlo su un'interfaccia di livello superiore come "RemovableIterator".

Se lo facessero, eviterebbero davvero alcuni problemi ma diciamo che abbiamo bisogno di un iteratore che possa anche impostare valori chiamati "SettableIterator" (implements setValue (T)) e anche un iteratore ripristinabile. Se richiediamo una combinazione di queste funzionalità, siamo costretti a dichiarare un'interfaccia per ogni combinazione. RessetableSetterIterator, RessetableRemovableIterator, RemovableSettableIterator, ecc. Le combinazioni crescono esponenzialmente alle funzionalità extra che aggiungiamo all'interfaccia.

Quello che di solito cerchiamo di esprimere è qualcosa come "questa funzione richiede un parametro che è Iterable, Settable e Ressetable" o "questa funzione restituisce un valore che è Iterable e Resettable". Eppure linguaggi come C #, Java e C ++ non ci permettono di farlo senza un uso scomodo dei generici.

Esistono metodi recenti che rendono obsoleto questo tipo di design?

    
posta Maxaon3000 27.09.2011 - 08:23
fonte

2 risposte

2

Lo scopo principale delle interfacce è di abilitare il riutilizzo del codice chiamante senza doverlo riscrivere per ogni possibile tipo di oggetto Iterator (o qualsiasi altra cosa). Nel tuo esempio, la violazione di sostituzione di Liskov elimina una buona porzione di quel codice da essere riutilizzata correttamente, ma questa particolare interfaccia è così estremamente diffusa che esiste una quantità significativa di codice riusabile anche con tale eliminazione. L'alternativa qui è ridisegnare la gerarchia in modo da prendere in considerazione gli iteratori non modificabili e nel processo è necessario riscrivere qualsiasi codice esistente per utilizzare le nuove classi, alcune delle quali potrebbero non avere origine. In altre parole, ci sono eccezioni ad ogni regola.

Si noti inoltre che non è necessario dichiarare una nuova interfaccia per ogni combinazione possibile, è sufficiente richiedere più interfacce. Non avresti bisogno di un RemovableResettableIterator , solo un RemovableIterator e ResettableIterator e richiedono l'uno o l'altro o entrambi, a seconda dei casi.

    
risposta data 27.09.2011 - 09:24
fonte
1

La risposta alla domanda del titolo è obiettivamente no . Esistono numerosi paradigmi nello sviluppo del software e l'OOP basato sull'eredità è tra i più riusciti perché funziona bene per molti problemi. Ciò non significa che non ci sia spazio per nuovi paradigmi o che non troveranno alcun successo.

Indipendentemente dai meriti di ogni nuovo paradigma o degli svantaggi dell'ereditarietà, l'inerzia da sola garantirà che l'eredità sarà con noi per qualche tempo a venire. E il fatto che al momento in cui scriviamo non abbia chiaramente articolato l'alternativa che dovrebbe essere l'oggetto della tua domanda mi porta a credere che il suo successore non sia immediatamente evidente.

    
risposta data 27.09.2011 - 09:04
fonte

Leggi altre domande sui tag