Coesão e Acoplamento são princípios de engenharia de software muito utilizados. Quando queremos ter uma arquitetura madura e sustentável, temos que levar em conta estes dois princípios, pois cada um deles tem um propósito específico que visa melhorar o design do software. O que acontece é que muitas pessoas não sabem a diferença entre eles e acabam não conseguindo obter os benefícios que colocá-los em prática na hora de se desenhar a arquitetura de um software.
Coesão está, na verdade, ligado ao princípio da responsabilidade única, que foi introduzido por Robert C. Martin no inicio dos anos 2000 e diz que uma classe deve ter apenas uma única responsabilidade e realizá-la de maneira satisfatória, ou seja, uma classe não deve assumir responsabilidades que não são suas . Uma vez sendo ignorado este princípio, passamos a ter problemas, como dificuldades de manutenção e de reuso. Observe o exemplo abaixo:
public class Programa
{
public void ExibirFormulario() {
//implementação
}
public void ObterProduto() {
//implementação
}
public void gravarProdutoDB {
//implementação
}
}
Como visto no exemplo acima, a classe Programa tem responsabilidades que não são suas, como obter um produto e gravá-lo no banco de dados. Então, dizemos que esta classe não está coesa, ou seja, ela tem responsabilidades demais, e o que é pior, responsabilidades que não são suas. Observe abaixo outro exemplo:
public class Programa
{
public void MostrarFormulario() {
//Implementação
}
public void BotaoGravarProduto( ) {
Produto.gravarProduto();
}
}
Vemos no exemplo acima, uma clara separação de responsabilidades, o que contribui para um design desacoplado e organizado. O formulário não assume o papel de cadastrar o produto, ele pede a quem tem a responsabilidade para que faça tal tarefa. O que temos que ter em mente é que uma classe deve ser responsável por exercer uma única responsabilidade e fazer outras classes cooperarem quando necessário. Já o acoplamento significa o quanto uma classe depende da outra para funcionar. E quanto maior for esta dependência entre ambas, dizemos que estas classes elas estão fortemente acopladas. O forte acoplamento também nos traz muitos problemas, problemas até semelhantes aos que um cenário pouco coeso nos traz. Observe o diagrama abaixo:
Como podemos ver na cadeia de classes acima, o forte acoplamento na mesma, torna muito custoso a sua manutenção e o seu gerenciamento, pois qualquer mudança vai afetar toda a cadeia de classes. A saída para cenários como este, é o que chamamos de Inversão de Controle que foi abordado em um post aqui. E uma maneira de mudar o quadro acima, seria inverter o controle e utilizar o padrão de injeção de dependência, para diminuir o acoplamento e evitar futuros problemas. Observe o diagrama abaixo com as devidas alterações:
Perceba como a dependência está na direção oposta, ou seja, não é mais de implementações concretas que estão baseados os relacionamentos entre as classes. Observe que utilizar abstrações, mantém um cenário que estará preparado para os impactos que as possíveis mudanças poderiam trazer.
Repare que a classe Produto se relaciona com uma abstração(interface) de DBWrapper, ou seja, tem uma classe chamada DBWrapperSqlServer que implementa esta interface, amanhã, o banco de dados passar a ser Oracle, basta adicionar uma classe DBWrapperOracle para atender a mudança de banco de dados,. Trabalhando desta maneira passamos a não ter medo das mudanças, pois em se tratando de software, elas irão ocorrer com muita frequência, e não tivermos um cenário suscetível a elas encontraremos sério problemas para evoluir o software.
Sabemos que no mundo “real” nem sempre podemos ter um cenário ideal, que é com um baixo acoplamento e uma alta coesão. Mas como arquitetos, temos que saber tomar a decisão correta, pois determinadas decisões não poderão ser revertidas, dependendo da fase em que estiver o projeto ou o tipo de decisão tomada. Ter classes com responsabilidades claras e um baixo acoplamento, embora não seja fácil de serem construídas, nos traz benefícios como baixo impacto em uma possível manutenção, gerenciamento e mudança no negócio facilitados. Também não podemos esquecer que as aplicações evoluem, mudam e, muitas das vezes, se transformam. Se ignorarmos as melhores práticas na hora de desenhar uma arquitetura, poderemos ter sérios problemas. E para nos auxiliar, temos o princípio da responsabilidade única e a inversão de controle, cujo objetivo é obter-se um cenário de responsabilidades claras entre nossas classes e um baixo acoplamento.