Quindi, probabilmente come molti, mi trovo spesso ad avere mal di testa con problemi di progettazione in cui, ad esempio, esiste un modello / approccio di progettazione che sembra adattarsi intuitivamente al problema e ha i benefici desiderati. Molto spesso c'è qualche avvertimento che rende difficile implementare il modello / approccio senza un qualche tipo di lavoro attorno al quale poi nega il beneficio del modello / approccio. Posso facilmente finire per iterare attraverso molti schemi / approcci perché prevedibilmente quasi tutti hanno alcuni avvertimenti molto significativi in situazioni del mondo reale in cui semplicemente non c'è una soluzione facile.
Esempio:
Ti darò un esempio ipotetico basato vagamente su uno reale che ho incontrato di recente. Diciamo che voglio usare la composizione sull'ereditarietà perché le gerarchie dell'ereditarietà hanno ostacolato la scalabilità del codice in passato. Potrei refactificare il codice ma poi scoprire che ci sono alcuni contesti in cui la superclasse / baseclass deve semplicemente chiamare funzionalità nella sottoclasse, nonostante i tentativi di evitarlo.
L'approccio migliore successivo sembra essere l'implementazione di un modello per metà delegato / osservatore e per metà composizione in modo che la superclasse possa delegare il comportamento o in modo che la sottoclasse possa osservare eventi di superclasse. Quindi la classe è meno scalabile e gestibile perché non è chiaro come debba essere estesa, inoltre è difficile estendere gli ascoltatori / delegati esistenti. Inoltre, le informazioni non sono nascoste bene perché si inizia a conoscere l'implementazione per vedere come estendere la superclasse (a meno che non si utilizzino i commenti in modo molto esteso).
Quindi dopo questo potrei semplicemente scegliere di usare osservatori o delegati completamente per evitare gli svantaggi che derivano dal mescolare pesantemente gli approcci. Tuttavia, questo ha i suoi problemi. Ad esempio, potrei scoprire che alla fine ho bisogno di osservatori o delegati per una quantità crescente di comportamenti fino a quando non ho bisogno di osservatori / delegati per praticamente ogni comportamento. Un'opzione potrebbe essere quella di avere solo un grande ascoltatore / delegato per tutto il comportamento, ma poi la classe di implementazione finisce con molti metodi vuoti ecc.
Quindi potrei provare un altro approccio, ma ci sono altrettanti problemi. Quindi il prossimo, quello dopo ecc.
Questo processo iterativo diventa molto difficile quando ogni approccio sembra avere tanti problemi quanti ne sono gli altri e porta a una sorta di paralisi delle decisioni di progettazione . È anche difficile accettare che il codice finisca allo stesso modo problematico indipendentemente da quale modello di progettazione o approccio viene utilizzato. Se finisco in questa situazione, significa che il problema stesso deve essere ripensato? Cosa fanno gli altri quando incontrano questa situazione?
Modifica: sembra che ci siano diverse interpretazioni della domanda che voglio chiarire:
- Ho completamente eliminato OOP dalla domanda perché si scopre che in realtà non è specifico di OOP, inoltre è troppo facile interpretare erroneamente alcuni dei commenti che ho fatto passando per OOP.
- Alcuni hanno affermato che dovrei adottare un approccio iterativo e provare schemi diversi o che dovrei scartare uno schema quando smette di funzionare. Questo è il processo a cui intendevo fare riferimento in primo luogo. Ho pensato che questo fosse chiaro dall'esempio, ma avrei potuto renderlo più chiaro, quindi ho modificato la domanda per farlo.