Design Pattern: Bridge
Continuando com nossos posts para ajudar a compreender o mundo dos Padrões de Proejto um jeito mais eficiente, no post de hoje vamos falar sobre o Bridge Pattern, que consiste em desacoplar obstáculos da implementação, com o objetivo de variação independente.
Então, vamos compreender o Bridge Pattern? Acompenhe a leitura!
Definição GOF
Desacoplar uma abstração de sua implementação para que as duas possam variar independentemente.
Você poderá observar em alguns locais ou literaturas que esse padrão também é conhecido como Handle ou Body Pattern, sendo assim através dele podemos dissociar uma classe de implementação de uma classe abstrata, fornecendo uma ponte (bridge) entre elas.
Essa Bridge torna a funcionalidade das classes concretas independente das classes do implementador da respectiva interface, portanto saiba que você pode alterar os diferentes tipos de classes estruturalmente sem afetar umas as outras, para um projeto grande com diversos profissionais envolvidos isso parece fantático, não?!
Utilizamos esse padrão normalmente quando queremos ocultar detalges de implementação, além disso evitamos um forte acoplamento, podemos até alterar a implementação sem a necessidade de recompilar a abstração através de divisão por bibliotecas por exemplo e também podemos compartilhar a implemtação entre outros objetos, sem necessidade sobre qualquer detalhe da implementação.
Inicialmente esse padrão pode parecer um tanto quanto complicado, por este motivo este artigo tem a promessa de ser algo claro, objetivo e direto para que você entenda em até 10 minutos o conceito e prática deste padrão, mas tenho certeza que através de nosso exemplo ‘hands on’, as ideias ficarão mais esclarecidas em sua mente.
Diagrama UML
Vamos a explicação de cada item deste Diagrama UML, segue:
- Abstraction — conforme nome já diz é uma classe abstrata onde contém membros definindo um objeto de negócio abstrato, com suas respectivas funcionalidades.
- RefinedAbstraction — Classe concreta que herda de Abstraction.
- Implementor — Está é a interface que atuará como ponte (Bridge) entre a abstração (Abstraction) e as classes de implementação (ConcreteImplementor), através desta ligação torna a(s) classe(s) de implementação independente da Abstração.
- ConcreteImplementor — Normalmente são mais de uma classe concreta, com detalhes da implementação para cada especificidade que estão de certa forma associadas a Abstração (Abstraction).
Problema
Pense no seguinte cenário, temos uma fábrica de veículo entre Motos e Carros, com suas respectivas cores como segue o diagrama abaixo.
Neste momento o programador logo pensa, Ok vou especializar o Carro que é Preto, assim como a Moto Preta e o Carro Cinza e assim por diante, com isso temos um cenário parecido com o diagrama a seguir, na qual temos uma explosão de classes com suas respectivas especialidades e até com muita repetição de código. Concorda?
Agora imagine o seguinte cenário, a fábrica decidiu aumentar o número de cores e também passar a produzir caminhonetes, com isso seu número de subclasses especializadas aumentaria de forma exponencial e seria o caos no seu projeto.
Pense então que podemos fazer melhor do que isso, na verdade a Interface de Cor poderia servir como ponte a classe veículo, ou seja, a interface Cor neste cenário seria a Implementor e Veículo seria a Abstraction, respectivamente Carro/Moto seriam RefinedAbstraction e as cores (Preto/Branco/Cinza) seriam ConcreteImplementor.
No diagrama acima podemos ver que não temos mais explosão alguma de subclasses, porém um uso independente das respectivas funcionalidades.
Implementação
Em nosso exemplo temos uma situação bancária, onde temos uma Conta de forma abstrata sendo representada por duas classes concretas de Conta Corrente e Conta Poupança que por sua vez devem realizar transferências bancárias de PIX e TED, lembrando que é uma visão didática para entendimento do padrão Bridge.
Conforme podemos observar no diagrama acima, a classe abstrata denominada Conta representa o Abstraction, assim como as classes concretas ContaCorrente e ContaPoupanca representam o RefinedAbstraction, por sua vez temos a interface ITransferencia representando o Implementor (Bridge) e para finalizar temos as classes concretas Pix e Ted representando ConcreteImplementor.
Acima temos a representação de Abstraction e RefinedAbstraction, observe que temos a realização da ponte (Bridge) através do construtor do Abstraction que se reflete para as classes concretas.
Para completar o padrão Bridge temos Implementor que seria a ponte entre os dois cenários (Conta x Transferência), assim como as implementações específicas através dos ConcreteImplementor.
Para finalizar temos a implementação do Client através da Program.cs, assim como o resultado final de nosso projeto.
Prós e Contras
Como efeito positivo temos o fraco acoplamento de seu código, aumento na produtividade quanto a manutenção do código assim como a reutilização do mesmo e facilitando as extensões. Porém, o efeito negativo que não devemos deixar de citar é um aumento significativo de complexidade no projeto.
Código Fonte
Baixe o código fonte em meu GitHub clicando neste link, implemente alguns ajustes no Padrão Bridge, coloque outras contas possíveis assim como operações e depois escreva nos comentários sobre seus ajustes.
Finalizando…
Muito obrigado a você que ficou até agora neste artigo, na próxima semana estaremos vendo sobre o Padrão Composite também da família Estrutural do GoF. Mais uma vez peço a você que gostou dê seu like, aplauda aqui no Medium ou até mesmo compartilhe com seus amigos e colegas de trabalho/faculdade/comunidade.
Forte abraço e até a próxima…