Il concetto di base è quello di astrarre ciò che cambia.
Se hai una serie di logiche che varia, considera il modello di strategia. Ciò implica un numero di classi che implementano tutte una singola interfaccia (o estendono un singolo tipo, a seconda della lingua che si sta utilizzando). L'implementazione appropriata viene istanziata e iniettata nell'oggetto chiamante. Questo è spesso implementato usando un framework per le dipendenze come Spring.
Ad esempio, potresti avere la tua classe di controllo, qualcosa come il questionario, che per la domanda 1 chiama un metodo nell'interfaccia di IQuestionOne. Questa interfaccia è implementata da classi diverse a seconda dell'anno: QuestionOne2013 contenente la logica 2013 e QuestionOne2014 contenente la logica 2014. Potresti quindi creare un Questionario per il 2013 e fare riferimento all'implementazione di QuestionOne2013 di IQuestionOne. Allo stesso modo, il questionario per il 2014 utilizzerà l'implementazione QuestionTwo2014.
Se la logica non cambia, puoi semplicemente riutilizzare la stessa implementazione. Quindi, forse la domanda 2 (astratta come l'interfaccia IQuestionTwo) ha la stessa logica per entrambi gli anni - usa semplicemente la stessa implementazione per entrambi i questionari.