Padrão Bridge
O que é o padrão Bridge?
O padrão Bridge é um padrão de design estrutural que tem a intenção de “desacoplar uma abstração de sua implementação, de modo que as duas possam variar independentemente”. Parece complexo? Vamos simplificar: imagine que você tem um controle remoto de TV. A forma como o controle funciona é a abstração, e a marca ou modelo do controle é a implementação. Com o padrão Bridge, você pode alterar a forma como o controle funciona ou mudar a marca ou modelo sem que um interfira no outro.
Quando usar o padrão Bridge?
Recomendo a utilização do padrão Bridge quando você quer evitar um vínculo permanente entre a abstração e a implementação. Isso pode ser útil quando a implementação deve ser selecionada ou alterada em tempo de execução.
using System;
// Abstração
abstract class Abstraction
{
protected Implementor implementor;
public Abstraction(Implementor implementor)
{
this.implementor = implementor;
}
public abstract void Operation();
}
// Implementação
interface Implementor
{
void OperationImp();
}
// Implementação Concreta A
class ConcreteImplementorA : Implementor
{
public void OperationImp()
{
Console.WriteLine("Implementação A sendo executada.");
}
}
// Implementação Concreta B
class ConcreteImplementorB : Implementor
{
public void OperationImp()
{
Console.WriteLine("Implementação B sendo executada.");
}
}
// Abstração Refinada
class RefinedAbstraction : Abstraction
{
public RefinedAbstraction(Implementor implementor) : base(implementor)
{
}
public override void Operation()
{
Console.WriteLine("Abstração sendo executada.");
implementor.OperationImp();
}
}
class Program
{
static void Main(string[] args)
{
// Cria as implementações concretas
Implementor implementorA = new ConcreteImplementorA();
Implementor implementorB = new ConcreteImplementorB();
// Cria a abstração refinada associada com a implementação A
Abstraction abstraction = new RefinedAbstraction(implementorA);
abstraction.Operation();
Console.WriteLine();
// Altera a implementação associada à abstração para a implementação B
abstraction.implementor = implementorB;
abstraction.Operation();
Console.ReadLine();
}
}
// Fonte: ChatGPT
Neste exemplo, temos a abstração Abstraction
que possui uma referência para a interface Implementor
. As classes ConcreteImplementorA
e ConcreteImplementorB
são as implementações concretas da interface Implementor
. A classe RefinedAbstraction
é uma abstração refinada que estende a classe Abstraction
. O programa principal cria as implementações concretas, associa a abstração refinada com a implementação A, executa a operação e, em seguida, altera a implementação para B e executa novamente a operação.
Padrão Adapter
O que é o padrão Adapter?
Agora vamos falar sobre o padrão Adapter. Ele é um padrão de design estrutural que permite que duas interfaces incompatíveis trabalhem juntas. É como um tradutor entre dois idiomas incompatíveis. Em outras palavras, o padrão Adapter cria uma ponte entre duas interfaces que de outra forma não poderiam trabalhar juntas devido a suas interfaces incompatíveis.
Quando usar o padrão Adapter?
Você deve considerar o uso do padrão Adapter quando quiser usar uma classe existente que seja incompatível com o restante do seu código. Ou quando quiser criar uma classe reutilizável que coopere com classes não relacionadas ou não previstas.
using System;
// Interface existente
interface ITarget
{
void Request();
}
// Classe existente
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Método SpecificRequest da classe Adaptee sendo chamado.");
}
}
// Adapter
class Adapter : ITarget
{
private Adaptee adaptee;
public Adapter(Adaptee adaptee)
{
this.adaptee = adaptee;
}
public void Request()
{
Console.WriteLine("Adapter chamando o método SpecificRequest da classe Adaptee.");
adaptee.SpecificRequest();
}
}
class Program
{
static void Main(string[] args)
{
// Cria a instância da classe Adaptee
Adaptee adaptee = new Adaptee();
// Cria o Adapter e passa a instância do Adaptee
ITarget target = new Adapter(adaptee);
// Chama o método Request do Adapter
target.Request();
Console.ReadLine();
}
}
// Fonte: ChatGPT
Neste exemplo, temos a interface ITarget
que define a interface esperada pelo cliente. A classe Adaptee
é a classe existente que possui uma interface incompatível com ITarget
. A classe Adapter
implementa a interface ITarget
e atua como um adaptador entre o cliente e a classe Adaptee
. No programa principal, criamos uma instância de Adaptee
, criamos um Adapter
passando a instância do Adaptee
e chamamos o método Request
do Adapter
, que internamente chama o método SpecificRequest
da classe Adaptee
.
Padrão Proxy
O que é o padrão Proxy?
Chegamos agora ao padrão Proxy. Esse padrão de design estrutural fornece um substituto ou espaço reservado para outro objeto para controlar o acesso a ele. É como um intermediário que pode adicionar funcionalidades extras ao objeto sem mudar sua interface.
Quando usar o padrão Proxy?
O padrão Proxy é útil quando você precisa controlar o acesso a um objeto, seja para adicionar uma camada de segurança, otimizar o desempenho, entre outros.
using System;
// Interface do objeto real e do proxy
interface ISubject
{
void Request();
}
// Objeto real
class RealSubject : ISubject
{
public void Request()
{
Console.WriteLine("RealSubject: Processando a requisição.");
}
}
// Proxy
class Proxy : ISubject
{
private RealSubject realSubject;
public void Request()
{
// Cria o objeto real sob demanda
if (realSubject == null)
{
Console.WriteLine("Proxy: Criando uma instância do RealSubject.");
realSubject = new RealSubject();
}
// Executa a requisição através do objeto real
realSubject.Request();
}
}
class Program
{
static void Main(string[] args)
{
// Cria o proxy
ISubject proxy = new Proxy();
// Chama o método Request do proxy
proxy.Request();
Console.ReadLine();
}
}
// Fonte: ChatGPT
Neste exemplo, temos a interface ISubject
que define a interface tanto para o objeto real (RealSubject
) quanto para o proxy (Proxy
). A classe RealSubject
representa o objeto real com a funcionalidade que desejamos controlar o acesso. O Proxy
atua como um substituto do objeto real e controla o acesso a ele. No programa principal, criamos uma instância do Proxy
e chamamos o método Request
, que internamente verifica se o objeto real já foi criado ou não. Se não foi criado, o Proxy
cria uma instância do RealSubject
e em seguida realiza a requisição através do objeto real.
Como esses padrões ajudam no design de sistemas flexíveis
Os padrões de design Bridge, Adapter e Proxy contribuem para o desenvolvimento de sistemas flexíveis e adaptáveis. Cada um desses padrões oferece uma maneira diferente de garantir que as partes do seu sistema possam variar independentemente umas das outras.
Como esses padrões podem beneficiar o negócio
Em um contexto de negócios, a utilização desses padrões de design pode trazer vários benefícios, como maior flexibilidade, redução de custos com manutenção e evolução do sistema, além de permitir a integração com outros sistemas de forma mais fácil.
Conclusão
Para finalizar, os padrões de design são ferramentas poderosas que podem ajudar a criar sistemas mais flexíveis, de fácil manutenção e interoperáveis. Espero que este artigo tenha ajudado a esclarecer a importância dos padrões Bridge, Adapter e Proxy no design de sistemas. Lembre-se: a melhor prática é sempre aquela que melhor se adequa ao seu caso!
Esse conteúdo é parte do material disponibilizado para os participantes do meu grupo de estudos de Padrões de Projeto. Você quer participar desse grupo? Clique aqui e veja como funciona.
Dúvidas Frequentes
Qual a diferença entre os padrões Bridge, Adapter e Proxy?
A principal diferença é a finalidade de cada um deles. O padrão Bridge é usado para separar a abstração da implementação, o Adapter é utilizado para compatibilizar interfaces incompatíveis, e o Proxy controla o acesso a objetos.
Os padrões de design podem ajudar no desenvolvimento de software?
Sim, os padrões de design podem ajudar no desenvolvimento de software, tornando-o mais organizado, eficiente e fácil de manter.
Todos os sistemas precisam usar esses padrões?
Não necessariamente. O uso de padrões depende dos requisitos e complexidade do sistema.
O uso de padrões de design pode ter um impacto negativo?
Se usados incorretamente, os padrões de design podem tornar o sistema excessivamente complexo e difícil de entender. É importante usar os padrões de design de forma adequada.
Qual padrão de design devo usar?
Depende das necessidades do seu sistema. Cada padrão tem suas próprias vantagens e desvantagens, e a decisão de usar um padrão específico deve ser baseada nas necessidades específicas do seu sistema.