In primo luogo, penso che ci sia una differenza fondamentale tra lo sviluppo iniziale (qui di una classe base) e le fasi successive dello sviluppo.
Se ti trovi nella categoria di sviluppo iniziale, avrai spesso bisogno di un refactoring per fare in modo che la classe base accolga la sua prima sottoclasse (a volte aggiungi un parametro, dividi un metodo, ecc ...), quindi riguardo un refactoring del bisogno, Non mi preoccuperei dell'OCP in una fase così precoce.
Inoltre, non possiamo e non dobbiamo cercare di prevedere tutti i possibili e potenziali usi futuri di qualcosa; fare questo è un anti-modello in sé.
Inoltre, c'è una differenza fondamentale tra classi interne e classi esposte esternamente. Nel caso di classi interne, potrebbero essere tutte versioni messe insieme (ad esempio nella stessa DLL), quindi non vi è alcun motivo per impedire il refactoring di ospitare nuove sottoclassi man mano che il design si evolve.
Tuttavia, per le API esposte esternamente che hanno la maturità di un certo numero di sottoclassi (o plug-in di terze parti) già implementate (che si può anche prevedere di aggiungere a diverse unità di versioning (es. diverse DLL), si dovrebbe prendere l'OCP sul serio: un design migliore può ospitare più sottocategorie di terze parti senza modifiche.
Tuttavia, per quanto riguarda le API esposte esternamente, è preferibile utilizzare le interfacce invece della sottoclassificazione. La sottoclasse limita seriamente le opzioni di un implementatore rispetto alle interfacce, complicando al tempo stesso le interazioni e amp; dipendenze tra produttori e consumatori. Utilizzando un'interfaccia, evitiamo semplicemente il problema se contrassegnare un metodo come virtuale o meno. Quando scegliamo le interfacce, i design diventano più disaccoppiati, il che è il più nello spirito dell'OCP.