Sou bastante pragmático, mas minha principal preocupação aqui é que você possa permitir que isso ConfigBlock
domine seus designs de interface de uma maneira possivelmente ruim. Quando você tem algo parecido com isto:
explicit MyGreatClass(const ConfigBlock& config);
... uma interface mais apropriada pode ser assim:
MyGreatClass(int foo, float bar, const string& baz);
... em vez de apenas escolher esses foo/bar/baz
campos de uma forma massivaConfigBlock
.
Design de Interface Preguiçoso
No lado positivo, esse tipo de design facilita o design de uma interface estável para o construtor, por exemplo, se você precisar de algo novo, basta carregá-lo em um ConfigBlock
(possivelmente sem nenhuma alteração no código) e, em seguida, escolha qualquer coisa nova que você precise sem nenhum tipo de alteração na interface, apenas uma alteração na implementação do MyGreatClass
.
Portanto, é um tanto prós e contras que isso o libera de projetar uma interface mais cuidadosa que aceita apenas as entradas de que realmente precisa. Ele aplica a mentalidade de "Apenas me dê esse enorme blob de dados, selecionarei o que preciso deles" em oposição a algo mais como preciso deles "Esses parâmetros precisos são o que essa interface precisa para funcionar".
Definitivamente, existem alguns profissionais aqui, mas eles podem ser superados pelos contras.
Acoplamento
Nesse cenário, todas essas classes sendo construídas a partir de uma ConfigBlock
instância acabam tendo suas dependências da seguinte maneira:
Isso pode se tornar uma PITA, por exemplo, se você quiser testar a unidade Class2
neste diagrama isoladamente. Pode ser necessário simular superficialmente várias ConfigBlock
entradas que contêm os campos relevantesClass2
está interessado para poder testá-lo sob uma variedade de condições.
Em qualquer tipo de novo contexto (seja teste de unidade ou projeto totalmente novo), essas classes podem acabar se tornando mais um fardo para (re) usar, pois acabamos sempre trazendo ConfigBlock
consigo o passeio e configurando-o adequadamente.
Reutilização / Implantação / Testabilidade
Em vez disso, se você projetar essas interfaces adequadamente, podemos dissociá-las ConfigBlock
e terminar com algo assim:
Se você observar neste diagrama acima, todas as classes se tornam independentes (seus acoplamentos aferentes / de saída são reduzidos em 1).
Isso leva a muito mais classes independentes (pelo menos independentes de ConfigBlock
), que podem ser muito mais fáceis de (re) usar / testar em novos cenários / projetos.
Agora, esse Client
código acaba sendo aquele que precisa depender de tudo e montar tudo junto. A carga acaba sendo transferida para esse código do cliente para ler os campos apropriados de a ConfigBlock
e passá-los para as classes apropriadas como parâmetros. No entanto, esse código do cliente geralmente é projetado de maneira restrita para um contexto específico, e seu potencial de reutilização normalmente será fechado ou fechado de qualquer maneira (pode ser a main
função do ponto de entrada do aplicativo ou algo parecido).
Portanto, do ponto de vista de reutilização e teste, pode ajudar a tornar essas classes mais independentes. Do ponto de vista da interface para aqueles que usam suas classes, também pode ajudar a declarar explicitamente quais parâmetros eles precisam, em vez de apenas um maciço ConfigBlock
que modela todo o universo de campos de dados necessários para tudo.
Conclusão
Em geral, esse tipo de design orientado a classe que depende de um monólito que possui tudo o que é necessário tende a ter esses tipos de características. Sua aplicabilidade, implantação, reutilização, testabilidade etc. podem ficar significativamente degradadas como resultado. No entanto, eles podem simplificar o design da interface se tentarmos dar uma olhada positiva nela. Cabe a você medir esses prós e contras e decidir se as compensações valem a pena. Normalmente, é muito mais seguro errar nesse tipo de design em que você escolhe um monólito em classes que geralmente se destinam a modelar um design mais geral e amplamente aplicável.
Por último mas não menos importante:
extern CodingBlock MyCodingBlock;
... isso é potencialmente ainda pior (mais distorcido?) em termos das características descritas acima do que a abordagem de injeção de dependência, pois acaba acoplando suas classes não apenas ConfigBlocks
, mas diretamente a uma instância específica . Isso degrada ainda mais a aplicabilidade / implantação / testabilidade.
Meu conselho geral seria errar ao projetar interfaces que não dependem desses tipos de monólitos para fornecer seus parâmetros, pelo menos para as classes mais aplicáveis que você cria. E evite a abordagem global sem injeção de dependência, se puder, a menos que você tenha realmente uma razão muito forte e confiante para não evitá-la.