Esse padrão não requer muitas apresentações, é também é bem simples, vamos pensar o que acontece na vida real... Utilizávamos nas nossas construções civis um padrão de tomadas e plugues, um belo dia saiu o padrão brasileiro de tomadas e plugues, quando você compra um aparelho que atende a essa norma logo pensa, vou ter que comprar um adaptador para adaptar esse plugue a tomada que esta em casa, pois são padrões (modelos) diferentes.
Bom com essa historia eu resumi a vida de um Adapter, que será uma classe intermediaria entre outras duas classes, Plugue e tomada.
Vamos criar um padrão com uma classe tomada e uma classe plugue para este padrão, vamos analisar essas classes.
Primeiro padrão:
#region [Padrao1]
public interface IPadrao1
{
String Nome { get; set; }
void testar();
}
public interface IPadraoTomada1 : IPadrao1
{
void Conectar(IPadrao1 _Plugue);
void Desconectar();
}
public class TomadaP1 : IPadraoTomada1
{
public String Nome { get; set; }
IPadrao1 Plugue;
public TomadaP1()
{
Nome = "TomadaP1";
}
public void testar()
{
if (Plugue != null)
{
Console.WriteLine("{0} está com o {1} conectado!", Nome, Plugue.Nome);
Plugue.testar();
}
else
{
Console.WriteLine("{0} está desconectado!", Nome);
}
}
public void Conectar(IPadrao1 _Plugue)
{
Plugue = _Plugue;
Console.WriteLine("{0} conectado!", Plugue.Nome);
}
public void Desconectar()
{
Plugue = null;
}
}
public class PlugueP1 : IPadrao1
{
public String Nome { get; set; }
public PlugueP1()
{
Nome = "PlugueP1";
}
public void testar()
{
Console.WriteLine("{0} funcionando.", Nome);
}
}
#endregion
Temos duas interfaces (IPadrao1 e IPadraoTomada1), e temos uma classe TomadaP1 que encapsula um Plugue do padrão IPradrao1, e com seus métodos Conectar, Desconectar e Teste. O plugue tem o método Teste.
Agora vamos ver o segundo padrão:
#region [Padrao2]
public interface IPadrao2
{
String Descricao { get; set; }
void Run();
}
public interface IPadraoTomada2 : IPadrao2
{
void Plugar(IPadrao2 _Plugue);
void Desplugar();
}
public class TomadaP2 : IPadraoTomada2
{
public String Descricao { get; set; }
IPadrao2 Plugue;
public TomadaP2()
{
Descricao = "TomadaP2";
}
public void Run()
{
if (Plugue != null)
{
Console.WriteLine("{0} está com o {1} conectado!", Descricao, Plugue.Descricao);
Plugue.Run();
}
else
{
Console.WriteLine("{0} está desconectado!", Descricao);
}
}
public void Plugar(IPadrao2 _Plugue)
{
Plugue = _Plugue;
Console.WriteLine("{0} conectado!", Plugue.Descricao);
}
public void Desplugar()
{
Plugue = null;
}
}
public class PlugueP2 : IPadrao2
{
public String Descricao { get; set; }
public PlugueP2()
{
Descricao = "PlugueP2";
}
public void Run()
{
Console.WriteLine("{0} funcionando.", Descricao);
}
}
#endregion
Também temos duas interfaces, e duas classes, o padrão1 e o padrão2 são respectivamente iguais, ambos servem para conectar e desconectar plugues de seu padrão.
Vamos testar os padrões separadamente.
class Program
{
static void Main(string[] args)
{
TomadaP1 Tomada1 = new TomadaP1();
TomadaP2 Tomada2 = new TomadaP2();
PlugueP1 PlugueP1 = new PlugueP1();
PlugueP2 PlugueP2 = new PlugueP2();
Tomada1.Conectar(PlugueP1);
Tomada1.testar();
Tomada1.Desconectar();
Tomada1.testar();
Tomada2.Plugar(PlugueP2);
Tomada2.Run();
Tomada2.Desplugar();
Tomada2.Run();
Console.ReadKey();
}
}
Mas como no mundo nada satisfaz a todos 100%, vamos imaginar temos que plugar um PlugueP1 em uma TomadaP2 ou vice e versa.
Bom, vamos recorrer ao Design Patterns Adapter, vamos criar um adaptador para ambos os casos.
Vamos criar as classes que serão os adaptadores dos plugues.
#region [Adapters]
public class PlugueP1Adapter : IPadrao1
{
IPadrao2 plugueP2;
public PlugueP1Adapter(IPadrao2 _PlugueP2)
{
plugueP2 = _PlugueP2;
}
public string Nome
{
get
{
return plugueP2.Descricao;
}
set
{
plugueP2.Descricao = value;
}
}
public void testar()
{
plugueP2.Run();
}
}
public class PlugueP2Adapter : IPadrao2
{
IPadrao1 plugueP1;
public PlugueP2Adapter(IPadrao1 _PlugueP1)
{
plugueP1 = _PlugueP1;
}
public string Descricao
{
get
{
return plugueP1.Nome;
}
set
{
plugueP1.Nome = value;
}
}
public void Run()
{
plugueP1.testar();
}
}
#endregion
As classes implementam a interface para qual classe será adaptada e encapsula um objeto da outra interface que será adaptado.
Desta forma, com o padrão Adapter conseguimos que uma classe X seja manipulada por um objeto que conhece somente a Y, pois passamos para a nossa tomada uma forma de controlar um objeto que ele não conhece e que não serve para ele, e o mais importante, não tivemos que alterar nada as classes alvos.
Chegamos ao fim deste artigo, espero novamente ter conseguido passar a idéia desse conceito. Até a próxima, ahh não se esqueçam de fazer o download do exemplo.
Fontes:
FREEMAN, ERIC & FREEMAN, ELISABETH – Use a Cabeça! Padrões de Projetos (Design Patterns), 2ª Edição [http://www.livrariasaraiva.com.br/produto/1995765/]