Più imparo sui diversi paradigmi di programmazione, come la programmazione funzionale, più comincio a mettere in discussione la saggezza dei concetti di OOP come eredità e polimorfismo. Ho imparato a conoscere l'eredità e il polimorfismo a scuola, e all'epoca il polimorfismo sembrava un modo meraviglioso di scrivere un codice generico che permettesse una facile estensibilità.
Ma di fronte alla tipizzazione anatra (sia dinamica che statica) e caratteristiche funzionali come le funzioni di ordine superiore, ho iniziato a considerare l'ereditarietà e il polimorfismo come l'imposizione di una restrizione non necessaria basata su un fragile insieme di relazioni tra oggetti. L'idea generale alla base del polimorfismo è che scrivi una funzione una volta, e successivamente puoi aggiungere nuove funzionalità al tuo programma senza cambiare la funzione originale - tutto ciò che devi fare è creare un'altra classe derivata che implementa i metodi necessari.
Ma questo è molto più semplice da ottenere attraverso la tipizzazione duck, sia che si tratti di un linguaggio dinamico come Python, sia di un linguaggio statico come C ++.
Ad esempio, considera la seguente funzione Python, seguita dal suo equivalente C ++ statico:
def foo(obj):
obj.doSomething()
template <class Obj>
void foo(Obj& obj)
{
obj.doSomething();
}
L'equivalente OOP sarebbe simile al seguente codice Java:
public void foo(DoSomethingable obj)
{
obj.doSomething();
}
La differenza principale, ovviamente, è che la versione Java richiede la creazione di un'interfaccia o di una gerarchia ereditaria prima che funzioni. La versione Java quindi richiede più lavoro ed è meno flessibile. Inoltre, trovo che la maggior parte delle gerarchie ereditarie del mondo reale siano alquanto instabili. Abbiamo visto tutti gli esempi inventati di forme e animali, ma nel mondo reale, poiché i requisiti aziendali cambiano e vengono aggiunte nuove funzionalità, è difficile svolgere qualsiasi lavoro prima di dover veramente allungare la relazione "is-a" tra sottoclassi, oppure rimodellare / riformattare la gerarchia per includere ulteriori classi base o interfacce al fine di soddisfare i nuovi requisiti. Con la tipizzazione anatra, non devi preoccuparti di modellare nulla: ti preoccupi solo della funzionalità di cui hai bisogno.
Tuttavia, ereditarietà e polimorfismo sono così popolari che dubito che sarebbe esagerato chiamarli la strategia dominante per estensibilità e riutilizzo del codice. Allora perché l'ereditarietà e il polimorfismo hanno così tanto successo? Sto trascurando alcuni seri vantaggi che l'ereditarietà / il polimorfismo hanno sulla dattilografia?
obj
non avesse undoSomething
metodo? Viene sollevata un'eccezione? Non succede niente?