Eu escrevi uma resposta anteriormente sobre Princípio Aberto-Fechado (OCP) vs Princípio de Substituição de Liskov (LSP) e ambos esses princípios se relacionam muito um com o outro, mas ainda são conceitualmente diferentes com alguns exemplos inventados de ter um, mas não o outro. Por causa dessa resposta, abordarei brevemente o OCP brevemente e aprofundarei o DIP e o que faz isso funcionar.
Vamos tentar discutir como o OCP se relaciona e difere do DIP (Dependency Inversion Principle), explicando primeiro os diferentes princípios.
Princípio de Inversão de Dependência
Lendo os Princípios de OOD do tio Bob, você verá que o DIP declara o seguinte:
Depende de abstrações, não de concreções.
Uma abstração em Java é simplesmente obtida com interface
e abstract
keywords, o que significa que você tem um "contrato" para alguma entidade de software que o código deve seguir. Algumas linguagens de programação não têm a capacidade de definir explicitamente comportamentos para o código seguir, portanto as abstrações devem ser seguidas de maneira mais manual, em vez de o compilador ajudá-lo a impor o contrato. Por exemplo, em C ++, você tem aulas com métodos virtuais e linguagens de programação dinâmica, como Javascript, para garantir que você use objetos da mesma maneira (embora, no caso de Javascript, isso tenha sido estendido no TypeScript, que adiciona um sistema de tipos para ajudá-lo). com contratos de escrita que são verificados pelo compilador).
O nome inclui o termo "inversão" porque, tradicionalmente (você sabe na idade das trevas da programação), você escrevia estruturas de software que tinham módulos de nível superior, dependendo dos módulos de baixo nível. Por exemplo, fazia sentido ter uma ButtonAtKitchen
entrada de manipulação para a KitchenLamp1
e KitchenLamp2
. Infelizmente, isso tornou o software muito mais específico do que precisava e o gráfico de objetos ficaria assim:
Então, quando você tornar o software mais geral, adicionando "contratos". Observe como as setas no gráfico do objeto "invertem" a direção. Que as lâmpadas da cozinha agora dependem de um Button
. Em outras palavras, os detalhes agora dependem de abstrações, e não o contrário.
Portanto, temos uma definição mais geral de DIP, também detalhada no artigo original de DIP por Tio Bob .
A. Os módulos de alto nível não devem depender dos módulos de baixo nível. Ambos devem depender da abstração. B. As abstrações não devem depender de detalhes. Os detalhes devem depender de abstrações.
Princípio Aberto-Fechado
Continuando com os princípios do tio Bob, você verá que o OCP declara o seguinte:
Você deve poder estender um comportamento de classe, sem modificá-lo.
Um exemplo disso é empregar o padrão Strategy em que uma Context
classe é fechada para modificações (por exemplo, você não pode alterar seu código interno), mas também está aberta para extensão por meio de suas dependências colaborativas (por exemplo, as classes de estratégia).
Em um sentido mais geral, qualquer módulo é construído para ser extensível através de seus pontos de extensão.
OCP é semelhante ao DIP, certo?
Não , não mesmo.
Embora ambos estejam discutindo abstrações, são conceitualmente diferentes. Ambos os princípios estão analisando contextos diferentes, OCP em um módulo específico e DIP em vários módulos. Você pode obter os dois ao mesmo tempo que a maioria dos padrões de design do Gang of Four, mas ainda pode se afastar do caminho.
No exemplo DIP mencionado acima, com o botão e as luminárias da cozinha, nenhuma das luminárias da cozinha é extensível (nem atualmente existe nenhum requisito para explicar que precisa ser). O design está quebrando o OCP, mas segue o DIP .
Um exemplo inverso (e artificial) seria uma lâmpada de cozinha extensível (com o ponto de extensão parecido com a LampShade
), mas o botão ainda depende das lâmpadas . Está quebrando o DIP, mas segue o OCP .
Não se preocupe, isso acontece
Na verdade, isso é algo que você verá acontecer frequentemente no código de produção, que parte dele pode quebrar um princípio. Em sistemas de software maiores (ou seja, qualquer coisa maior que os exemplos acima), você pode quebrar um princípio, mas mantendo o outro normalmente porque precisa manter o código simples. Na minha opinião, isso é bom para módulos pequenos e independentes, pois estão no contexto relacionado ao Princípio de Responsabilidade Única (SRP).
Uma vez que algum módulo se torna complicado, você provavelmente precisará analisá-lo com todos os princípios em mente e reprojetar ou refatorá- lo para um padrão bem conhecido.