Comprendo l'intento del principio aperto-chiuso. Ha lo scopo di ridurre il rischio di rompere qualcosa che già funziona durante la modifica, dicendoti di provare a estenderlo senza modificarlo.
Tuttavia, ho avuto qualche difficoltà a capire come questo principio viene applicato nella pratica. Per quanto ne so, ci sono due modi per applicarlo. Prima e dopo un possibile cambiamento:
Prima: programma sulle astrazioni e "predire il futuro" il più possibile. Ad esempio, un metodo
drive(Car car)
dovrà cambiare in caso diMotorcycle
aggiunta di s al sistema in futuro, quindi probabilmente viola OCP. Ma il metodo hadrive(MotorVehicle vehicle)
meno probabilità di cambiare in futuro, quindi aderisce all'OCP.Tuttavia, è abbastanza difficile prevedere il futuro e sapere in anticipo quali modifiche verranno apportate al sistema.
Dopo: quando è necessaria una modifica, estendi una classe invece di modificarne il codice corrente.
La pratica n. 1 non è difficile da capire. Tuttavia è pratica n. 2 che ho difficoltà a capire come applicare.
Per esempio (l'ho preso da un video su YouTube): diciamo che abbiamo un metodo in una classe che accetta CreditCard
gli oggetti: makePayment(CraditCard card)
. Un giornoVoucher
vengono aggiunti al sistema. Questo metodo non li supporta, quindi deve essere modificato.
Quando abbiamo implementato il metodo in primo luogo, non siamo riusciti a prevedere il futuro e programmare in termini più astratti (ad esempio makePayment(Payment pay)
, quindi ora dobbiamo cambiare il codice esistente.
La pratica n. 2 dice che dovremmo aggiungere la funzionalità estendendo invece di modificare. Cosa significa? Dovrei sottoclassare la classe esistente invece di cambiare semplicemente il suo codice esistente? Dovrei creare una sorta di wrapper attorno ad esso solo per evitare di riscrivere il codice?
Oppure il principio non fa nemmeno riferimento a "come modificare / aggiungere correttamente la funzionalità", ma piuttosto a "come evitare di dover prima apportare modifiche (ad esempio, il programma alle astrazioni)?