Vamos olhar para isso praticamente
Obj 3
agora sabe que Obj 4
existe. E daí? Por que nos importamos?
MERGULHO diz
"Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações."
OK, mas não são todas as abstrações de objetos?
DIP também diz
"Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações."
OK, mas se meu objeto estiver encapsulado corretamente, isso não oculta nenhum detalhe?
Algumas pessoas gostam de insistir cegamente que todo objeto precisa de uma interface de palavra-chave. Eu não sou um deles. Eu gosto de insistir cegamente que, se você não vai usá-los agora, precisa de um plano para lidar com a necessidade de algo como eles mais tarde.
Se o seu código for totalmente refatorável a cada versão, você poderá extrair as interfaces posteriormente, se precisar delas. Se você publicou um código que não deseja recompilar e deseja estar falando através de uma interface, precisará de um plano.
Obj 3
sabe que Obj 4
existe. Mas Obj 3
sabe se Obj 4
é concreto?
É por isso que é tão bom NÃO se espalhar por new
toda parte. Se Obj 3
não souber se Obj 4
é concreto, provavelmente porque não o criou, então se você Obj 4
entrar mais tarde e se transformar em uma classe abstrataObj 3
, não se importaria.
Se você pode fazer isso, Obj 4
foi totalmente abstrato o tempo todo. A única coisa que faz uma interface entre eles desde o início é a garantia de que alguém não adicionará acidentalmente código que denuncie que Obj 4
é concreto agora. Construtores protegidos podem atenuar esse risco, mas isso leva a outra pergunta:
Os Obj 3 e 4 estão no mesmo pacote?
Os objetos geralmente são agrupados de alguma forma (pacote, espaço para nome, etc). Quando agrupados com sabedoria, altere os impactos mais prováveis dentro de um grupo do que entre grupos.
Eu gosto de agrupar por recurso. Se Obj 3
eObj 4
estiver no mesmo grupo e camada, é muito improvável que você tenha publicado um e não queira refatorá-lo enquanto precisar alterar apenas o outro. Isso significa que é menos provável que esses objetos se beneficiem de uma abstração colocada entre eles antes que haja uma necessidade clara.
Se você estiver cruzando um limite de grupo, é realmente uma boa ideia permitir que os objetos de ambos os lados variem independentemente.
Deveria ser simples, mas infelizmente o Java e o C # fizeram escolhas infelizes que complicam isso.
Em C #, é tradição nomear cada interface de palavra-chave com um I
prefixo. Isso força os clientes a SABERem que estão conversando com uma interface de palavras-chave. Isso mexe com o plano de refatoração.
Em Java, é tradição usar um melhor padrão de nomenclatura: no FooImple implements Foo
entanto, isso só ajuda no nível do código-fonte, pois o Java compila interfaces de palavras-chave com um binário diferente. Isso significa que, quando você refatorar Foo
clientes concretos para abstratos que não precisam de um único caractere de código alterado, ainda precisará ser recompilado.
São esses BUGS nessas linguagens específicas que impedem as pessoas de adiar a abstração formal até que realmente precisem. Você não disse qual idioma está usando, mas entende que existem alguns idiomas que simplesmente não têm esses problemas.
Você não disse qual o idioma que está usando, portanto, pedimos que você analise seu idioma e situação com cuidado antes de decidir que serão interfaces de palavras-chave em todos os lugares.
O princípio YAGNI desempenha um papel fundamental aqui. Mas o mesmo acontece com "Por favor, torne difícil dar um tiro no meu pé".