Substituindo dependências diretas por mensagens

Às vezes, um módulo só precisa notificar os outros que alguns eventos/mudanças ocorreram nele, e não importa o que aconteça com essa informação posteriormente.

Nesse caso, os módulos não precisam “se conhecer” de forma alguma, ou seja, conter links diretos e interagir diretamente, mas basta apenas trocar mensagens (messages) ou eventos (eventos).

Às vezes, parece que a comunicação do módulo via mensagens é muito mais fraca do que a dependência direta. De fato, como os métodos não são chamados, não há informações sobre as classes. Mas isso não passa de uma ilusão.

Em vez de nomes de métodos, a lógica começa a ser vinculada a tipos de mensagens, seus parâmetros e dados transmitidos. A conectividade de tais módulos é manchada.

Costumava ser assim: chamamos métodos - há conectividade, não chamamos métodos - não há conectividade. Agora imagine que o módulo A começou a enviar dados ligeiramente diferentes em suas mensagens. E, ao mesmo tempo, todos os módulos dependentes dessas mensagens não funcionarão corretamente.

Suponha que, anteriormente, ao adicionar um novo usuário, o módulo de autorização enviasse a mensagem USER_ADDED e, após a atualização, passasse a enviar esta mensagem ao tentar se registrar e, adicionalmente, indicar registro bem-sucedido ou não nos parâmetros.

Portanto, é muito importante implementar o mecanismo de mensagem com muita competência. Existem vários modelos para isso.

Observador. É usado no caso de dependência um-para-muitos, quando muitos módulos dependem do estado de um - o principal. Ele usa o mecanismo de mailing, o que significa que o módulo principal simplesmente envia as mesmas mensagens para todos os seus assinantes, e os módulos interessados ​​nessas informações implementam a interface “assinante” e se inscrevem na lista de discussão.

Essa abordagem é amplamente utilizada em sistemas com interface de usuário, permitindo que o núcleo da aplicação (modelo) permaneça independente enquanto informa suas interfaces associadas que algo mudou e precisa ser atualizado.

Aqui, o formato da mensagem é padronizado no nível do sistema operacional, cujos desenvolvedores devem cuidar da compatibilidade com versões anteriores e da boa documentação.

A organização da interação por meio da distribuição de mensagens tem um “bônus” adicional - a existência opcional de “assinantes” para mensagens “publicadas” (ou seja, enviadas). Um sistema bem projetado como este permite que os módulos sejam adicionados/removidos a qualquer momento.

Barramento de mensagens

Você pode organizar a troca de mensagens e usar o padrão Mediator para isso de uma forma diferenciada .

É usado quando há uma dependência muitos-para-muitos entre os módulos. O mediador atua como um intermediário na comunicação entre os módulos, atuando como um centro de comunicação e eliminando a necessidade de os módulos se referirem explicitamente uns aos outros.

Como resultado, a interação dos módulos entre si (“todos com todos”) é substituída pela interação dos módulos apenas com um intermediário (“um com todos”). Diz-se que o mediador encapsula a interação entre vários módulos.

Barramento de mensagens

Este é o chamado intermediário inteligente . É lá que os desenvolvedores geralmente começam a adicionar suas muletas, que influenciam o comportamento de módulos individuais ligando / desligando o recebimento de certas mensagens.

Um exemplo típico da vida real é o controle de tráfego do aeroporto. Todas as mensagens das aeronaves vão para a torre de controle do controlador em vez de serem enviadas diretamente entre as aeronaves. E o controlador já toma decisões sobre quais aviões podem decolar ou pousar e, por sua vez, enviar mensagens aos aviões.

Importante! Os módulos podem enviar uns aos outros não apenas mensagens simples, mas também objetos de comando. Essa interação é descrita pelo modelo de comando . O resultado final é encapsular uma solicitação para executar uma ação específica como um objeto separado.

Na verdade, esse objeto contém um único método execute() , que permite que você passe essa ação para outros módulos para execução como um parâmetro e geralmente execute quaisquer operações com o objeto de comando que podem ser executadas em objetos comuns.

Lei de Deméter

A Lei de Deméter proíbe o uso de dependências implícitas: "O objeto A não deve ser capaz de acessar diretamente o objeto C se o objeto A tiver acesso ao objeto B e o objeto B tiver acesso ao objeto C."

Isso significa que todas as dependências no código devem ser “explícitas” - as classes/módulos só podem usar “suas dependências” em seu trabalho e não devem passar por elas para outros. Um bom exemplo é uma arquitetura de três camadas. A camada de interface deve funcionar com a camada lógica, mas não deve interagir diretamente com a camada de banco de dados.

Resumidamente, esse princípio também é formulado da seguinte forma: "Interaja apenas com amigos imediatos e não com amigos de amigos". Isso consegue menos coerência do código, bem como maior visibilidade e transparência de seu design.

A Lei de Deméter implementa o já mencionado “princípio do conhecimento mínimo”, que é a base do baixo acoplamento e consiste no fato de que um objeto/módulo deve conhecer o mínimo de detalhes possível sobre a estrutura e propriedades de outros objetos/módulos e qualquer coisa em geral, incluindo seus próprios componentes .

Uma analogia da vida: se você quer que o cachorro corra, é estúpido comandar as patas, é melhor dar o comando ao cachorro, e ela mesma cuidará das patas.

Composição em vez de herança

Este é um tópico muito grande e interessante e merece pelo menos uma palestra separada. Muitas cópias foram quebradas sobre esse assunto na Internet até que um consenso fosse alcançado - usamos herança ao mínimo, composição - ao máximo.

O ponto é que a herança realmente fornece a conexão mais forte entre as classes, por isso deve ser evitada. Este tópico é bem abordado no artigo de Herb Sutter " Prefer Composition Over Inheritance ".

Ao começar a aprender padrões de projeto, você encontrará vários padrões que governam a criação de um objeto ou sua estrutura interna. A propósito, posso aconselhar neste contexto a prestar atenção ao padrão Delegado / Delegado e ao padrão Componente , que veio dos jogos .

Falaremos mais sobre padrões um pouco mais tarde.

undefined
3
Опрос
Software architecture, client-server architecture, MVC,  14 уровень,  9 лекция
недоступен
Software architecture, client-server architecture, MVC
Software architecture, client-server architecture, MVC