Acho que essa pode ser uma meta-resposta controversa e estou um pouco atrasada para a festa, mas acho que é muito importante mencionar isso aqui, porque acho que sei de onde você vem.
O problema com a maneira como os padrões de design são usados é que, quando ensinados, eles apresentam um caso como este:
Você tem esse cenário específico. Organize seu código dessa maneira. Aqui está um exemplo inteligente, mas um tanto artificial.
O problema é que, quando você começa a fazer engenharia de verdade, as coisas não são tão simples assim. O padrão de design sobre o qual você leu não se encaixa perfeitamente no problema que você está tentando resolver. Sem mencionar que as bibliotecas que você está usando violam totalmente tudo o que é declarado no texto, explicando esses padrões, cada um de sua maneira especial. E, como resultado, o código que você escreve "parece errado" e você faz perguntas como esta.
Além disso, gostaria de citar Andrei Alexandrescu, ao falar sobre engenharia de software, que afirma:
A engenharia de software, talvez mais do que qualquer outra disciplina de engenharia, exibe uma rica multiplicidade: você pode fazer a mesma coisa de muitas maneiras corretas, e há infinitas nuances entre certo e errado.
Talvez isso seja um exagero, mas acho que isso explica perfeitamente um motivo adicional pelo qual você pode se sentir menos confiante no seu código.
É em tempos como este que a voz profética de Mike Acton, líder de motores de jogos da Insomniac, grita na minha cabeça:
CONHEÇA SEUS DADOS
Ele está falando sobre as entradas para o seu programa e as saídas desejadas. E depois há esta gema de Fred Brooks do Mythical Man Month:
Mostre-me seus fluxogramas e oculte suas mesas, e continuarei confuso. Mostre-me suas tabelas e geralmente não precisarei de seus fluxogramas; eles serão óbvios.
Portanto, se eu fosse você, raciocinaria sobre o meu problema com base no meu caso de entrada típico e se alcançaria a saída correta desejada. E faça perguntas como esta:
- Os dados de saída do meu programa estão corretos?
- É produzido com eficiência / rapidez para o meu caso de entrada mais comum?
- Meu código é fácil o suficiente para raciocinar localmente, tanto para mim quanto para meus colegas de equipe? Caso contrário, posso simplificar?
Quando você faz isso, a pergunta "quantas camadas de abstração ou padrões de design são necessários" torna-se muito mais fácil de responder. Quantas camadas de abstração você precisa? Tantos quanto necessário para atingir esses objetivos, e não mais. "E os padrões de design? Eu não usei nenhum!" Bem, se os objetivos acima foram alcançados sem a aplicação direta de um padrão, tudo bem. Faça com que funcione e passe para o próximo problema. Comece com seus dados, não com o código.