8.1 Decomposição é tudo
Para maior clareza, uma imagem de um bom artigo "Decoupling of Object-Oriented Systems", ilustrando os principais pontos que serão discutidos.
Você ainda acha que projetar uma arquitetura de aplicativo é fácil?
8.2 Interfaces, ocultação de implementação
Os principais princípios para reduzir o acoplamento do sistema são os princípios de OOP e o princípio de Encapsulamento + Abstração + Polimorfismo por trás deles.
Por isso:
- Os módulos devem ser "caixas pretas" uns para os outros (encapsulamento) . Isso significa que um módulo não deve “subir” em outro módulo e saber nada sobre sua estrutura interna. Objetos em um subsistema não devem acessar diretamente objetos em outro subsistema.
- Os módulos/subsistemas devem interagir entre si apenas por meio de interfaces (ou seja, abstrações que não dependem de detalhes de implementação). Assim, cada módulo deve ter uma interface ou interfaces bem definidas para interagir com outros módulos.
O princípio da "caixa preta" (encapsulamento) permite considerar a estrutura de cada subsistema independentemente de outros subsistemas. O módulo, que é uma "caixa preta", pode ser alterado de forma relativamente livre. Os problemas podem surgir apenas na junção de diferentes módulos (ou um módulo e um ambiente).
E essa interação deve ser descrita da forma mais geral (abstrata), ou seja, na forma de uma interface. Nesse caso, o código funcionará da mesma forma com qualquer implementação que esteja em conformidade com o contrato de interface. É essa capacidade de trabalhar com diferentes implementações (módulos ou objetos) por meio de uma interface unificada que se chama polimorfismo.
Por isso Servlet é uma interface : o container web não sabe nada sobre servlets, pois são alguns objetos que implementam a interface Servlet e pronto. Servlets também sabem um pouco sobre a estrutura do container. A interface Servlet é esse contrato, esse padrão, essa interação mínima necessária para fazer com que os aplicativos Java da Web dominem o mundo.
O polimorfismo não é de forma alguma a substituição de métodos, como às vezes se acredita erroneamente, mas antes de tudo, a intercambialidade de módulos / objetos com a mesma interface ou “uma interface, muitas implementações”. Para implementar o polimorfismo, o mecanismo de herança não é necessário. É importante entender isso porque a herança em geral deve ser evitada sempre que possível .
Graças às interfaces e polimorfismo, é precisamente a capacidade de modificar e estender o código sem alterar o que já está escrito (Princípio Aberto-Fechado).
Desde que a interação dos módulos seja descrita exclusivamente na forma de interfaces e não esteja vinculada a implementações específicas, você tem a oportunidade de substituir de forma absolutamente “indolor” para o sistema um módulo por qualquer outro que implemente a mesma interface, bem como adicione um novo e, assim, expanda a funcionalidade.
É como no construtor LEGO - a interface padroniza a interação e serve como uma espécie de conector onde qualquer módulo com um conector adequado pode ser conectado.
A flexibilidade do designer é garantida pelo fato de podermos simplesmente substituir um módulo ou peça por outro com os mesmos conectores (com a mesma interface), bem como adicionar quantas peças novas quisermos (ao mesmo tempo, as existentes partes não são alteradas ou alteradas de forma alguma).
As interfaces permitem construir um sistema mais simples, considerando cada subsistema como um todo e ignorando sua estrutura interna. Eles permitem que os módulos interajam e, ao mesmo tempo, não saibam nada sobre a estrutura interna um do outro, implementando totalmente o princípio do conhecimento mínimo, que é a base do acoplamento fraco.
Quanto mais gerais/abstratas forem definidas as interfaces e quanto menos restrições elas impõem à interação, mais flexível é o sistema. A partir daqui, segue-se mais um dos princípios do SOLID - o Princípio de Segregação de Interface , que se opõe a “interfaces espessas”.
Ele diz que interfaces grandes e volumosas devem ser divididas em interfaces menores e mais específicas, para que os clientes de interfaces pequenas (dependendo dos módulos) saibam apenas sobre os métodos com os quais precisam trabalhar.
Este princípio é formulado da seguinte forma: “Os clientes não devem depender de métodos (esteja ciente dos métodos) que não usam” ou “Muitas interfaces especializadas são melhores do que uma universal”.
Acontece que a conectividade fraca é fornecida apenas quando a interação e as dependências dos módulos são descritas apenas com a ajuda de interfaces, ou seja, abstrações, sem o uso de conhecimento sobre sua estrutura interna e estrutura... E, de fato, o encapsulamento é implementado. Além disso, temos a capacidade de expandir/alterar o comportamento do sistema adicionando e usando diferentes implementações, ou seja, devido ao polimorfismo. Sim, voltamos a OOP - Encapsulamento, Abstração, Polimorfismo.
8.3 Fachada: interface do módulo
Aqui, um programador experiente perguntará: se o design não está no nível dos objetos que implementam as interfaces correspondentes, mas no nível dos módulos, qual é a implementação da interface do módulo?
Resposta: falando na linguagem dos padrões de design, um objeto especial pode ser responsável pela implementação da interface do módulo - Facade . Se você estiver chamando métodos em um objeto que contém o sufixo Gateway (por exemplo, MobileApiGateway), provavelmente é uma fachada.
Uma fachada é um objeto de interface que acumula um conjunto de operações de alto nível para trabalhar com um determinado subsistema, escondendo sua estrutura interna e verdadeira complexidade por trás dele . Fornece proteção contra alterações na implementação do subsistema. Serve como um único ponto de entrada - "você chuta a fachada e ele sabe quem precisa ser chutado neste subsistema para conseguir o que precisa".
Você acaba de ser apresentado a um dos padrões de design mais importantes que permite usar o conceito de interfaces ao projetar módulos e, assim, desacoplá-los - "Fachada".
Além disso, "Facade" permite trabalhar com módulos da mesma forma que com objetos comuns e aplicar todos os princípios e técnicas úteis que são usados \u200b\u200bno design de classes ao projetar módulos.
Nota : Embora a maioria dos programadores entenda a importância das interfaces ao projetar classes (objetos), parece que muitos descobrem a ideia de usar interfaces também no nível do módulo.
Você acaba de ser apresentado a um dos padrões de design mais importantes que permite usar o conceito de interfaces ao projetar módulos e, assim, desacoplá-los - "Fachada".
Além disso, "Facade" permite trabalhar com módulos da mesma forma que com objetos comuns e aplicar todos os princípios e técnicas úteis que são usados \u200b\u200bno design de classes ao projetar módulos.
Nota : Embora a maioria dos programadores entenda a importância das interfaces ao projetar classes (objetos), parece que muitos descobrem a ideia de usar interfaces também no nível do módulo.
GO TO FULL VERSION