Perché l'ereditarietà è vista generalmente come una brutta cosa dai sostenitori dell'OOP [duplicato]

15

Continuo a sentire l'espressione "Favorisci la composizione sull'ereditarietà" di GoF, che viene ripetutamente infastidita dal mio amico che pensa che si tratti di una dichiarazione generale valida, ma non è più ragionevole considerare che la vera ragione per cui esiste l'ereditarietà non è solo per il riutilizzo del comportamento, ma nel caso in cui una gerarchia di classi ereditate dallo stesso antenato debba essere passata come argomenti a una funzione, per implementare implicitamente il polimorfismo e queste classi discendenti hanno metodi che sono polimorfismi di una funzione nella classe ancestrale. L'uso dell'ereditarietà in questo modo è l'unico motivo per cui branchi e flotte di programmatori trovano piacevole scrivere l'interfaccia utente con Microsoft WPF con (Visual) C #. In che modo la composizione si adatta perfettamente all'immagine del design della struttura dell'interfaccia utente senza essere troppo prolissa?

So che gli scontri di compatibilità possono derivare dall'uso dell'ereditarietà, che è una delle cose che la dichiarazione intende proteggere, ma non si tratta di una cattiva progettazione da parte del programmatore (incapacità di discernere quando ereditare e quando comporre) piuttosto che sul paradigma o sul linguaggio?

PS: ho usato i termini antenato e discendente per evitare di implicare la profondità dell'ereditarietà attraverso l'uso di genitore e figlio.

    
posta RonaldMunodawafa 19.10.2014 - 00:14
fonte

2 risposte

22

Chiedete perché, come se il se sia deciso. Consideriamo le tue supposizioni:

Why is inheritance generally viewed as a bad thing by OOP proponents

Non sono d'accordo con la premessa della domanda. L'ereditarietà non è generalmente considerata cattiva, è vista come abusata e abusata.

I modelli di progettazione GoF non dicono nulla di negativo.

Vediamo cosa dicono in effetti i Pattern Design di GoF ...

  1. p20 - Nella discussione su Favor composition over inheritance , che Eredità e composizione degli oggetti lavorano quindi insieme .
  2. p22 - La composizione degli oggetti ti consente di modificare il comportamento che viene composto in fase di esecuzione, ma richiede anche l'indirizzamento indiretto e può essere meno efficiente.
  3. p25 - ... d'altra parte, l'uso intensivo della composizione degli oggetti può rendere i disegni più difficili da capire.

E così via. Ora, ci sono anche molti aspetti negativi dell'eredità che potrei citare, ma il punto è che GoF non pretende che l'eredità sia cattiva e insegna chiaramente i pro ei contro di varie tecniche. Cosa significa favour in questo contesto? Non rendere l'eredità la tua prima scelta. Un po 'come non rendere il piede di porco la tua prima scelta, prova prima la chiave.

Per quanto riguarda l'ereditarietà, esistono due tipi principali: ereditarietà di classe e ereditarietà dell'interfaccia (sottotipizzazione). Entrambi sono appropriati per modelli particolari, ma quest'ultimo è diventato favorevole da quando è stato pubblicato GoF. Se stavi imparando l'OOP nei primi anni '90, sapresti del Metodo Booch e del Metodo Rumbaugh, ma oggi ne senti poco. Eppure stavano insegnando a una generazione di programmatori C ++ (e Java) ad ereditare e scavalcare. Ma lo stato dell'arte è andato avanti. Abbiamo, attraverso l'esperienza collettiva, scoperto che l'accoppiamento libero si trova davvero attraverso l'uso di interfacce e iniezione di dipendenza, e non semplicemente usando l'incapsulamento.

Il problema con l'ereditarietà è troppi I programmatori "OO" pensano ai problemi prima come potenziali soluzioni di ereditarietà. L'ereditarietà è un concetto concreto che le persone capiscono rapidamente all'inizio, così tante persone si attaccano a questo e non crescono mai molto di più come modellisti di sistemi. Quando tutto in un sistema è incuneato in una gerarchia di ereditarietà e il codice viene riutilizzato dall'ereditarietà della classe, si ottengono risultati disastrosi e i benefici di OO sono superati dalla lotta effettiva con la stessa gerarchia. Ho visto molti progetti, e sono stato responsabile per alcuni di me stesso, che hanno trascorso più tempo a lottare su un'enorme gerarchia che a mantenere le interfacce del sottosistema. Questo è un segno di abuso di ereditarietà.

Ma a parte questo, l'eredità è inestimabile per realizzare molte cose buone. Il polimorfismo (in particolare il polimorfismo del sottotipo) è uno strumento molto potente e la distribuzione singola e doppia è la chiave per modelli come il pattern Visitor. L'ereditarietà dell'interfaccia è la chiave per progettare interfacce, non implementazioni. Le classi o le interfacce astratte sono utili solo con l'ereditarietà.

Se il tuo amico pensa che "favorire la composizione sull'eredità" è un mantra per evitare del tutto l'eredità, si sbaglia e non capisce il concetto di un set di strumenti completo.

Sembra che non abbia effettivamente letto GoF. Se ha affermato di leggerlo, sembra che abbia frainteso e dovrebbe leggerlo di nuovo.

    
risposta data 19.10.2014 - 01:56
fonte
6

...my friend who thinks it is a valid blanket statement but is it not more sensible to...

Sì, è sempre più sensato (tempo permettendo) capire perché le cose sono come sono, piuttosto che seguire un mantra alla cieca.

real reason why inheritance exists is not just for behaviour reuse but for the case where a hierarchy of classes inheriting from the same ancestor need to be passed as arguments to a function

Non corretto. Questo è un dettaglio di implementazione dei linguaggi e, anche se abbastanza significativo, non quello su cui dovresti concentrarti.

to implicitly implement polymorphism and these descendent classes have methods which are polymorphisms of a funtion in the ancestral class.

E anche questo non è del tutto corretto.

is it not a question of bad design on the programmer's part (failure to discern when to inherit and when to compose) rather than on the paradigm or language?

È interamente una questione di cattivo design da parte del programmatore. Il disprezzo generale per l'ereditarietà non è per l'ereditarietà del concetto, è perché l'ereditarietà viene usata nel codice che causa dolore.

Perché l'ereditarietà (e tutti i sottotipi) è una specializzazione di alcuni super-tipi. Non solo, ma l'ereditarietà ben fatta è una specializzazione dei contratti definiti dal tipo super (altrimenti l'intera Rectangle / Square cosa funzionerebbe effettivamente). Anche quando i programmatori sanno che dovrebbero farlo (e pochissimi lo fanno). È difficile perfezionare i contratti del tipo senza interrompere altre parti dei contratti (vedere i comportamenti Width / Height in Rectangle / Square per un esempio). E peggio ancora, non è particolarmente comune che voglia di fare effettivamente quella specializzazione limitata dal momento che raramente è utile.

Quindi, c'è un carico di barche di programmatori che usano male l'ereditarietà, solo per fare il polimorfismo, o per avere XY e Z (virare su un campo in più è un uso fragile e spesso pericoloso di ereditarietà) o per tipo specializzare le cose (sì, Penguin è un Bird , ma è .Fly() il metodo non funziona ...), o ...

Quindi l'ereditarietà è vista come una cosa generalmente negativa dato che generalmente produce risultati sbagliati.

    
risposta data 19.10.2014 - 01:21
fonte

Leggi altre domande sui tag