Penso che potresti trovare utile un mio post sul blog su astrazioni che perdono. Ecco lo sfondo rilevante:
L'astrazione è un meccanismo per aiutare a prendere ciò che è comune tra un insieme di frammenti di programma correlati, rimuovere le loro differenze e consentire ai programmatori di lavorare direttamente con un costrutto che rappresenta quel concetto astratto. Questo nuovo costrutto (praticamente) ha sempre delle parametrizzazioni : un mezzo per personalizzare l'uso del costrutto in base alle proprie esigenze specifiche.
Ad esempio, una List
classe può sottrarre i dettagli di un'implementazione dell'elenco collegato, dove invece di pensare in termini di manipolazione next
e previous
puntatori, puoi pensare a livello di aggiunta o rimozione di valori a una sequenza. L'astrazione è uno strumento essenziale per creare funzionalità utili, ricche e talvolta complesse da un insieme molto più piccolo di concetti più primitivi.
L'astrazione è correlata all'incapsulamento e alla modularità e questi concetti sono spesso fraintesi.
Nel List
esempio, incapsulamento può essere utilizzato per nascondere i dettagli di implementazione di una lista collegata; in un linguaggio orientato agli oggetti, ad esempio, è possibile rendere privati i puntatori next
e previous
, dove solo l'implementazione dell'elenco ha accesso a questi campi.
L'incapsulamento non è sufficiente per l'astrazione, perché non implica necessariamente che tu abbia una nuova o diversa concezione dei costrutti. Se tutta una List
classe ti fornisse metodi di accesso stile ' getNext
' / ' setNext
', ti incapsulerebbe dai dettagli di implementazione (ad esempio, hai chiamato il campo ' prev
' o ' previous
'? Qual era il suo tipo statico?), Ma avrebbe un livello molto basso di astrazione.
La modularità riguarda il nascondere le informazioni : le proprietà stabili sono specificate in un'interfaccia e un modulo implementa tale interfaccia, mantenendo tutti i dettagli di implementazione all'interno del modulo. La modularità aiuta i programmatori a far fronte al cambiamento, perché altri moduli dipendono solo dall'interfaccia stabile.
Il nascondere le informazioni è aiutato dall'incapsulamento (in modo che il codice non dipenda da dettagli di implementazione instabili), ma l'incapsulamento non è necessario per la modularità. Ad esempio, è possibile implementare una List
struttura in C, esponendo le ' next
' e ' prev
puntatori' al mondo, ma anche fornire un'interfaccia, che contiene initList()
,addToList()
eremoveFromList()
funzioni. A condizione che vengano seguite le regole dell'interfaccia, è possibile garantire che determinate proprietà rimarranno sempre valide, ad esempio garantendo che la struttura dei dati sia sempre in uno stato valido. [Il classico documento di Parnas sulla modularità, per esempio, è stato scritto con un esempio in assemblea. L'interfaccia è un contratto e una forma di comunicazione sul design, non deve necessariamente essere controllata meccanicamente, anche se questo è ciò su cui facciamo affidamento oggi.]
Sebbene termini come astratto, modulare e incapsulato siano usati come descrizioni positive del design, è importante rendersi conto che la presenza di una di queste qualità non ti dà automaticamente un buon design:
Se un algoritmo n ^ 3 è "ben incapsulato", funzionerà comunque peggio di un algoritmo n log n migliorato.
Se un'interfaccia si impegna in un sistema operativo specifico, nessuno dei vantaggi di un design modulare verrà realizzato quando, per esempio, un videogioco deve essere trasferito da Windows a iPad.
Se l'astrazione creata espone troppi dettagli inessenziali, non riuscirà a creare un nuovo costrutto con le sue operazioni: sarà semplicemente un altro nome per la stessa cosa.