Quando utilizzare le classi e quando utilizzare le funzioni POD (PDS) +

0

Recentemente, ho letto un post sul blog, che non riesco a trovare, su come dobbiamo "liberare i dati". Il punto principale del post era che usassimo troppo le classi e l'incapsulamento poiché molti problemi possono essere risolti con meno overhead usando la semplice struttura dati passiva (passiva) combinata con l'overload di funzioni. Il post ha aumentato la mia consapevolezza circa il costo di creazione (e mantenimento) di classi e classi di gerarchie. Per condividere questa nuova consapevolezza con i miei colleghi, ho cercato di individuare le condizioni che giustificano la creazione di classi. Finora, ho trovato

  • Presenza di un invariante. Ad esempio, una mappa dovrebbe sempre contenere lo stesso numero di chiavi ed elementi. Non vuoi che l'utente aggiunga una chiave e dimentichi di aggiungere l'elemento corrispondente.
  • Nascondere l'implementazione per avere la libertà di cambiarlo facilmente. Ad esempio, un Punto può essere codificato con coordinate cartesiane (x, y) o con un raggio e un angolo.
  • Manipolazione omogenea. Ad esempio se vuoi Cane e Cat essere manipolati allo stesso modo perché sono entrambi specializzati nel concetto più generale di Animale .

Quali sono gli altri motivi per creare classi o classi di gerarchie?

Modifica: Per costo , mi riferisco al tempo, denaro e Debito tecnico necessario per creare e mantenere gerarchie di classi e classi. Questo costo dovrebbe essere paragonato al costo di altre soluzioni.

Modifica 2: Mi sono reso conto che provare a rendere questa domanda generale era un errore. Ho sicuramente in mente il c ++.

    
posta Kevin 14.07.2016 - 21:49
fonte

2 risposte

1

Questa è una domanda molto ampia, in quanto dipende dalla lingua utilizzata e dalle funzioni offerte dalla lingua:

  • Le "solide vecchie strutture dati" possono essere rese immutabili?
  • Il linguaggio impone l'incapsulamento di funzioni e dati privati o è per convenzione?
  • La lingua è tipizzata in modo statico o dinamico?
  • Permette funzioni al di fuori delle classi statiche?
  • Tratta le funzioni come valori di prima classe?
  • Supporta le interfacce?
  • Supporta record, strutture ecc?
  • Supporta anche le classi?

A seconda delle risposte alle domande precedenti, la strategia utilizzata varierà. Se, ad esempio, la lingua non supporta le classi, non le userete ...

Detto questo, ci sono alcune regole generali che possono essere seguite in tutte le lingue:

  1. Evita lo stato globale. Se disponi di dati, che sono accessibili a livello globale ed è modificabile, sei sulla strada per il debug dell'inferno. Basta non farlo.
  2. Evitare l'accoppiamento. Che si tratti di oggetti che ruotano su istanze di altre classi o funzioni codificate per chiamare altre funzioni pubbliche, si sta rendendo il codice più difficile da testare e mantenere. Utilizzare tecniche di iniezione e mantenere l'accoppiamento il più libero possibile.
  3. Evita l'ereditarietà . L'ereditarietà causa problemi di accoppiamento, incluso il problema di classe base fragile , indebolisce l'incapsulamento e causa problemi di test. A meno che tu non stia usando un linguaggio che può solo ottenere il polimorfismo attraverso l'ereditarietà (cioè non supporta classi o interfacce veramente astratte), allora non usare l'ereditarietà.

Come regola generale, per un tipico linguaggio moderno che supporta funzioni e classi statiche:

  1. Mantieni i dati il più possibile immutabili,
  2. Mantieni i dati e le funzionalità il più distinti possibile,
  3. Ma usa gli oggetti per incapsulare lo stato e fornire metodi per gestire tale stato,
  4. Usa le funzioni (metodi statici) solo quando possono essere pure , ovvero producono un risultato dai parametri in modo deterministico senza effetti collaterali.
  5. Progettare su interfacce (o l'equivalente) e utilizzare l'iniezione il più possibile.
risposta data 15.07.2016 - 10:15
fonte
0

Classi contro "dati liberi" + funzioni

La libertà dei dati è sempre a scapito della libertà del programmatore:

  • Con un POD sei libero di fare ciò che vuoi. E quello che vuoi, lo implementerai in una funzione ben sovraccaricata.
  • Ma anche altri programmatori (o il tuo futuro te stesso) sono liberi di fare ciò che vogliono ed esprimere la loro creatività. Sono liberi di spararsi ai piedi se non prestano molta attenzione a quello che fanno.
  • Inoltre, non appena esponi un POD pubblicamente, non è più una libertà: è un debito tecnico istantaneo! Perché, poiché non hai più il controllo su come vengono utilizzati i dati, non hai più il potere di modificare la struttura come desideri (ad esempio se decidessi di sostituire un giorno intero, un mese, un anno con un singolo campo data). Le modifiche richiederebbero un'attenta analisi di tutto il codice utilizzando questi dati.
  • Nei piccoli sistemi con un paio di programmatori puoi imporre una certa disciplina che mitiga questi rischi. Tuttavia, nella programmazione a livello di grandi (motori di veicoli spaziali, centrali nucleari, sistemi di telecomunicazione), con migliaia di programmatori, tale visibilità causerà inevitabilmente bug o dipendenze indesiderate che ostacolano la manutenibilità futura. È statistico.

Questo è il motivo per cui sono stati compiuti tanti sforzi nei linguaggi di programmazione per controllare la visibilità dei dati e le funzioni sono state un problema nei sistemi di grandi dimensioni, dal momento che i primi giorni della programmazione strutturata:

  • Nel mondo pre-object oriented, questo ha portato al concetto di modulo di Simula che è stato sviluppato ulteriormente in linguaggi come Modula2 o ADA.
  • Nelle lingue più recenti orientate agli oggetti, questo ha portato al concetto di classe. La classe ti consente, tra l'altro, di creare e gestire più istanze con estrema facilità mentre nei moduli non hai questa facitabilità.

Quello che cerco di dire sopra è che la disciplina delle classi ti dà più libertà di quanto pensi. È solo una questione di punto di vista (cioè il proprietario della classe rispetto al consumatore).

Quali classi possono fare di più

Come hai detto, le classi possono fare più di dati gratuiti con funzioni:

  • incapsulamento e separazione delle preoccupazioni
  • astrazione dati
  • l'ereditarietà passando da una classe generale a più specifiche
  • polimorfismo, consentendo l'invocazione di funzioni / metodi specifici di una classe senza sapere in fase di compilazione quale classe sarà l'oggetto

Le classi sono anche un blocco di edifici per ulteriori libertà:

  • Abbiamo assistito nelle principali lingue all'emergere della programmazione generica, che consente di definire una funzione generica indipendentemente dai dati che deve manipolare.
  • Anche il concetto di design pattern è stato un passo avanti. È difficile immaginare tali modelli implementati con POD e funzioni. (In effetti posso immaginarlo, perché l'ho fatto per anni in un linguaggio non orientato agli oggetti: funziona ma con quale complessità ...)

Conclusione

Come conclusione, una citazione da Bjarne Stroustrup :

Do we really need multiple inheritance? Not really. We can do without multiple inheritance by using workarounds, exactly as we can do without single inheritance by using workarounds. We can even do without classes by using workarounds. (...) The reason languages provide inheritance (...) is that language-supported inheritance is typically superior to workarounds (e.g. use of forwarding functions to sub-objects or separately allocated objects) for ease of programming, for detecting logical problems, for maintainability, and often for performance.

    
risposta data 15.07.2016 - 00:14
fonte

Leggi altre domande sui tag