ereditarietà e polimorfismo riducono la leggibilità

-3

La maggior parte delle app finanziarie hanno calcoli complessi e nel tempo hanno cambiamenti nei metodi di calcolo. Quindi crei per lo più una nuova versione per la tua classe di calcolatrice che estende la calcolatrice precedente e sovrascrive un metodo.

Puoi estendere la nuova calcolatrice dalla vecchia versione perché eviterai il codice ripetuto e userai il typecasting nei vantaggi di ereditarietà nel tuo programma.

Ma c'è un grosso problema, il calcolo è un processo complesso e quando si utilizza l'ereditarietà su quello, la leggibilità della calcolatrice diminuirà nel tempo ed è molto difficile per i nuovi programmatori leggerlo e comprenderlo.

Ora saprò che esiste una soluzione o un modello di progettazione per l'implementazione di processi complessi? Penso a un semplice flusso di lavoro o a un modello di progettazione strategica, ma conoscerò la tua esperienza nell'affrontare problemi simili.

Grazie.

Aggiornamento:

La mia domanda non riguarda la frase seguente:
   - Perché preferisco soprattutto la composizione sull'ereditarietà sul problema dell'ereditarietà a vantaggio della composizione rispetto all'ereditarietà.
La mia domanda riguarda la tua esperienza su un problema comune sulla leggibilità del codice in problemi di dominio complessi come il calcolo che l'ereditarietà può ridurre la leggibilità.

    
posta Rasoul Taheri 11.08.2016 - 21:57
fonte

3 risposte

11

Né l'ereditarietà né il polimorfismo diminuiscono la leggibilità. L'uso di qualsiasi concetto OOP per i motivi sbagliati lo fa.

Evitare codice ripetuto non è un buon motivo per usare l'ereditarietà, puoi farlo isolando parti di codice in metodi della stessa classe. È necessaria una relazione "è una" per giustificare l'eredità. Una nuova calcolatrice non è una sorta di vecchio calcolatore. Posso immaginare se tu avessi un calcolatore astratto di classe base se tutti i calcolatori pensabili nel tuo dominio problematico offrissero lo stesso set di funzionalità, solo con diverse implementazioni.

    
risposta data 11.08.2016 - 22:50
fonte
4

Se sei un po 'miope e guardi solo le tue classi di calcolo, allora sì, forse usare un po' di ereditarietà e polimorfismo può rendere il tuo codice un po 'più difficile da leggere, perché tutto non è in un posto. So che può essere difficile per alcuni sviluppatori seguire un codice che non è completamente lineare.

D'altra parte, se le tue responsabilità aumentano mai e lavori sul programma più grande che usa le tue classi di calcolo, tra dozzine di altre classi e oggetti nella soluzione generale, posso garantire quell'ereditarietà e il polimorismo rendono la tua vita molto più semplice.

Ad esempio, se stai lavorando su un sistema di flusso di lavoro che deve essere in grado di chiamare una varietà di classi di calcolo, è molto utile se derivano tutte da una classe base. Quindi puoi scrivere cose come

void ExecuteComputation(BaseObject computerObject)
{
    computerObject.Execute();
}

Altrimenti dovrai scrivere un po 'di spazzatura come questa:

void ExecuteComputation(object computerObject)
{
    if (computerObject is ComputerType1) { ((ComputerType1)computerObject).ExecuteThis())};
    if (computerObject is ComputerType2) { ((ComputerType2)computerObject).ExecuteThat())};
    if (computerObject is ComputerType3) { ((ComputerType3)computerObject).ExecuteThisOtherThing())};
}

che non solo è meno leggibile, ma pone un grave problema di manutenibilità, specialmente se si sperava in una sorta di separazione delle preoccupazioni tra il sistema del flusso di lavoro e le classi di calcolo.

Il problema diventa ancora più grave quando si lavora con sistemi distribuiti, terze parti e reti di informazione. Avere astrazioni di base e implementazioni concrete che ereditano da quelle astrazioni di base rende possibile la messaggistica che è indipendente dal trasporto, ad esempio, e le interfacce e i contratti rendono possibile l'architettura orientata ai servizi e lo sviluppo parallelo.

Inoltre, senza ereditarietà e astrazione, non ci sarebbe inversione di controllo, iniezione di dipendenza o test di unità automatizzato. Fondamentalmente avresti buttato fuori tutte le innovazioni tecniche degli ultimi dieci anni. Buona fortuna.

    
risposta data 20.08.2016 - 02:58
fonte
0

La tua domanda sembra aver ereditato un grande sistema legacy di cui occuparti e stai cercando un modello di design magico che lo renda semplice.

È tutto a causa dell'ereditarietà?

Siamo onesti: qualsiasi sistema di maggiori dimensioni sembra complesso e difficile da capire a prima vista. Questo a causa delle questioni complesse con cui hanno a che fare.

Il sistema deve essere scomposto in parti più piccole e comprensibili. Ma quale sarebbe l'alternativa all'eredità nel tuo caso? Sub-routine di calcolo piatto che scrivono tutto ancora e ancora con un sacco di parametri per indicare le variabili e la variante di calcolo da utilizzare?

Questo non produrrebbe un codice ancora più difficile in cui non sei mai sicuro che se cambi qualcosa in una formula non dovresti adattare altre formule altrove? Non vorresti poi postare una domanda come ho ereditato 200K righe di codice spaghetti - e ora? .

È complesso o complicato ?

Tuttavia, il codice è scritto, più classi hai, più difficile sarà capire. È naturale.

Alcuni psicologi sostengono addirittura che il nostro cervello ha in media una capacità di memoria a breve termine di circa 7 item, e cercare di capire l'interrelazione simultanea tra più item sembra difficile. Secondo loro, l'unico modo per superare questa limitazione sarebbero gli elementi del cluster. E l'ereditarietà è proprio così: puoi gestire l'oggetto derivato come l'oggetto originale, con solo le variazioni di cui avresti bisogno. Quindi dovrebbe essere più semplice da capire.

Ciò che è difficile da padroneggiare è il modo in cui tutte le classi sono correlate. Non solo nella loro struttura statica, ma anche in che modo interagiscono dinamicamente in fase di esecuzione.

Come è progettato il tuo sistema?

La lettura del codice può darti una visione dettagliata, classe per classe. Con un buon IDE, non dovrebbe esserci un problema per navigare tra classi correlate e trovare tutti i pezzi di codice relativi.

Ma questo non è sufficiente per ottenere la prospettiva e la comprensione generale del sistema:

The worst possible documentation to create for an object-oriented system is a stand-alone description of the semantics of each method on a class-by-class basis. This approach tends to generate a great deal of useless documentation that no one reads or trusts, and fails to document the more important architectural issues that transcend individual classes, namely, the collaborations among classes and objects.

- Grady Booch in Object-Oriented Analysis and Design

Ad esempio, è una pratica comune definire relazioni di alto livello tra classi astratte, per ridurre le dipendenze nelle classi concrete derivate. Ma questo rende facile perdere di vista queste relazioni quando si implementano le lezioni concrete. Ed a volte è difficile indovinare l'intento dietro l'astrazione.

Soluzione

Sfortunatamente, non esiste un modello di progettazione per scopi generali per superare la complessità. Non esiste una soluzione: per prima cosa devi comprendere a fondo il tuo sistema:

  • Se esiste un documento di progettazione architettonica, iniziare da quello.
  • In caso contrario, effettuare un reverse engineering. Inizia con un diagramma di classe. Esistono strumenti automatici che possono aiutarti.
  • Quindi, se hai familiarità con i modelli di progettazione, prova a identificare nella struttura alcuni schemi di progettazione esistenti. Questo accelererà la tua comprensione della relazione dinamica tra le classi.

Forse con una comprensione più profonda scoprirai che il codice è strutturato meglio di quanto pensavi. E forse no. E in questo caso puoi tornare con ulteriori domande specifiche, per le quali possiamo fornire alcune idee su specifici modelli di progettazione per il miglioramento.

    
risposta data 20.08.2016 - 11:14
fonte

Leggi altre domande sui tag