Adapter: diferenças entre revisões
Linha 67: | Linha 67: | ||
O Padrão [[Bridge]] – tem uma estrutura semelhante, porem tem por definição separar uma interface de sua aplicação, um adaptador se destina a mudar a interface de uma classe/objeto já existente. |
O Padrão [[Bridge]] – tem uma estrutura semelhante, porem tem por definição separar uma interface de sua aplicação, um adaptador se destina a mudar a interface de uma classe/objeto já existente. |
||
O Padrão [[ |
O Padrão [[Façade]] – Em ambos os padrões, Façade e Adapter, existe um classe (ou classes) que precisam de uma interface necessária, entretanto, o Facade simplifica uma interface, ao passo que o Adapter converte para uma já existente adaptando-a ao projeto.<ref>{{referência a livro|Autor=FREEMAN, Eric|Título=Use a Cabeça!PADRÕES DE PROJETO|Subtítulo=DESIGN PATTERNS|Editora= Alta Books|Local de publicação= Rio de Janeiro|Ano=2007|Edição=2|ID={{ISBN|9788576081746}}}}</ref> |
||
==Implementações== |
==Implementações== |
Revisão das 13h38min de 16 de novembro de 2011
Adapter, O Adapter (tambem conhecido como Wrapper), é classificado como um padrão estrutural, faz com que uma interface adaptada seja compatível com outra, fornecendo uma abstração de diferentes interfaces. O Adapter faz com que classes com interfaces incompatíveis trabalhem em conjunto.[1]
Padrão de projeto de software Adapter.[2]
O padrão abrange tanto o escopo de classe como tambem de objetos, sendo que o primeiro utiliza herança multipla e é utilizado quando o alvo é uma interface, já o de objetos utiliza agregação pois o alvo que necessita ser adaptado é uma classe.
O Adapter possui 3 elementos importantes, o Alvo, classe ou interface que desejamos implementar o Adapter, outro elemento é o próprio Adapter, possibilita a junção de duas classes diferentes, e por último o Adaptado, classe que contém os métodos e funcionalidades acessados pelo Alvo.
Um exemplo usual do conceito de Adapter é o uso de tomadas em países diferentes, cada pais adota um padrão, para resolver esse problema usa-se um adaptador que convertem um tipo de adaptador em outro. Em programação funciona da mesma forma, o Adapter funciona como um elo de ligação de duas classes diferentes. Um outro exemplo de sua utilização pode ser visto na API da linguagem Java para tratamento de eventos (MouseAdapter, WindowAdapter).
As tomadas têm uma interface, que dizem se ela é uma tomada de dois ou de três pinos. Essa interface deve possuir um método que diz o que a tomada faz: fornecer energia elétrica. Os plugues também deverão ter interfaces que dirão se eles são plugues de dois ou três pinos e possuirão um método para conectá- lo a uma tomada. Um plugue de 3 pinos só pode se conectar a uma tomada de 3 pinos e um plugue de 2 pinos a uma tomada de 2 pinos.
Precisamos encaixar um plugue de três pinos em uma tomada de dois pinos, portanto deveremos usar um adaptador.
- Sem um adaptador uma interface não converte para outra, portanto um adaptador irá se comportar como uma tomada de 3 pinos.
- Cria-se um adaptador com uma referencia para o objeto adaptado.
- Implementa-se a interface TomadaTresPinos como uma forma de traduzir o comportamento da interface adaptada.
Quando usar Adapter ?
- Quando precisar inserir uma nova classe em um projeto e as interfaces forem diferentes.
- Se quiser criar classes reutilizáveis que cooperem com futuras classes imprevistas.
- Quando precisar utilizar varias subclasses, sendo impraticável implementar uma interface para cada uma.
Adaptador de Objetos[3].
- O cliente só vê a interface ClasseAbstrata, só o Adapter sabe da existência do cliente e da classe adaptada.
- A classe Adaptador que implementa a Classe Abstrata.
- O Adaptador se comunica com a Classe Desejada.
- Todas as solicitações são feitas a Classe Desejada.
Como o Adapter vincula o Cliente a um interface, pode-se usar vários adaptadores cada um deles com diferentes classes e subclasses. A desvantagem dos Adaptadores de Objeto é em relação a implementação, é preciso escrever todo o código necessário para as chamadas da classe adaptada.
Adaptador de Classes
Requer a utilização de herança múltipla.
O Adapter funciona como um interpretador, a classe Cliente utiliza a classe Alvo, todos os métodos chamados pelo cliente pertence a esse classe, a classe Adaptado não possui os métodos da classe Alvo, o trabalho do Adaptador é traduzir as chamadas dos métodos da classe Alvo em chamada aos métodos da classe Adaptado.A implementação de Adaptadores de Classes é muito mais simples do que Adaptadores de Objetos, pois normalmente envolve menos código.
Aplicabilidade
Use o padrão quando:
- Precisar utilizar uma classe existente, entretanto sua interface não corresponde a interface que utiliza.
- Criar uma classe reutilizável que coopere com classes não-reutilizáveis ou previstas.
- Classes com interfaces incompatíveis.
- Precisar utilizar varias subclasses.
Padrões Relacionados
O Padrão Bridge – tem uma estrutura semelhante, porem tem por definição separar uma interface de sua aplicação, um adaptador se destina a mudar a interface de uma classe/objeto já existente.
O Padrão Façade – Em ambos os padrões, Façade e Adapter, existe um classe (ou classes) que precisam de uma interface necessária, entretanto, o Facade simplifica uma interface, ao passo que o Adapter converte para uma já existente adaptando-a ao projeto.[4]
Implementações
Pseudocódigo
C#
using System; class MainApp { static void Main() { // Create adapter and place a request Target target = new Adapter(); target.Request(); // Wait for user Console.Read(); } } // "Target" class Target { public virtual void Request() { Console.WriteLine("Called Target Request()"); } } // "Adapter" class Adapter : Target { private Adaptee adaptee = new Adaptee(); public override void Request() { // Possibly do some other work // and then call SpecificRequest adaptee.SpecificRequest(); } } // "Adaptee" class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } }
C++
#include <iostream.h> typedef int Coordinate; typedef int Dimension; // Desired interface class Rectangle { public: virtual void draw() = 0; }; // Legacy component class LegacyRectangle { public: LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2) { x1_ = x1; y1_ = y1; x2_ = x2; y2_ = y2; cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => (" << x2_ << "," << y2_ << ")" << endl; } void oldDraw() { cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_ << ") => (" << x2_ << "," << y2_ << ")" << endl; } private: Coordinate x1_; Coordinate y1_; Coordinate x2_; Coordinate y2_; }; // Adapter wrapper class RectangleAdapter: public Rectangle, private LegacyRectangle { public: RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h): LegacyRectangle(x, y, x + w, y + h) { cout << "RectangleAdapter: create. (" << x << "," << y << "), width = " << w << ", height = " << h << endl; } virtual void draw() { cout << "RectangleAdapter: draw." << endl; oldDraw(); } }; int main() { Rectangle *r = new RectangleAdapter(120, 200, 60, 40); r->draw(); }
Delphi
unit Adapter; interface uses SysUtils, Classes; type //The new class TNewCustomer = class private FCustomerID: Longint; FFirstName: string; FLastName: string; FDOB: TDateTime; protected function GetCustomerID: Longint; virtual; function GetFirstName: string; virtual; function GetLastName: string; virtual; function GetDOB: TDateTime; virtual; public constructor Create(CustID: Longint); virtual; property CustomerID: Longint read GetCustomerID; property FirstName: string read GetFirstName; property LastName: string read GetLastName; property DOB: TDateTime read GetDOB; end; //An interface method //Lets us hide details of TOldCustomer from the client function GetCustomer(CustomerID: Longint): TNewCustomer; implementation const Last_OldCustomer_At_Year_2000 = 15722; Last_OldCustomer_In_Database = 30000; //The new class constructor TNewCustomer.Create(CustID: Longint); begin FCustomerID := CustID; FFirstName := 'A'; FLastName := 'New_Customer'; FDOB := Now; end; function TNewCustomer.GetCustomerID: Longint; begin Result := FCustomerID; end; function TNewCustomer.GetFirstName: string; begin Result := FFirstName; end; function TNewCustomer.GetLastName: string; begin Result := FLastName; end; function TNewCustomer.GetDOB: TDateTime; begin Result := FDOB; end; type //The old class TOldDOB = record Day: 0..31; Month: 1..12; Year: 0..99; end; TOldCustomer = class FCustomerID: Integer; FName: string; FDOB: TOldDOB; public constructor Create(CustID: Integer); property CustomerID: Integer read FCustomerID; property Name: string read FName; property DOB: TOldDOB read FDOB; end; constructor TOldCustomer.Create(CustID: Integer); begin FCustomerID := CustomerID; FName := 'An Old_Customer'; with FDOB do begin Day := 1; Month := 1; Year := 1; end; end; type //The Adapter class TAdaptedCustomer = class(TNewCustomer) private FOldCustomer: TOldCustomer; protected function GetCustomerID: Longint; override; function GetFirstName: string; override; function GetLastName: string; override; function GetDOB: TDateTime; override; public constructor Create(CustID: Longint); override; destructor Destroy; override; end; //The Adapter class constructor TAdaptedCustomer.Create(CustID: Longint); begin inherited Create(CustID); FOldCustomer := TOldCustomer.Create(CustID); end; destructor TAdaptedCustomer.Destroy; begin FOldCustomer.Free; inherited Destroy; end; function TAdaptedCustomer.GetCustomerID: Longint; begin Result := FOldCustomer.CustomerID; end; function TAdaptedCustomer.GetFirstName: string; var SpacePos: integer; begin SpacePos := Pos(' ', FOldCustomer.Name); if SpacePos = 0 then Result := '' else Result := Copy(FOldCustomer.Name,1,SpacePos-1); end; function TAdaptedCustomer.GetLastName: string; var SpacePos: integer; begin SpacePos := Pos(' ', FOldCustomer.Name); if SpacePos = 0 then Result := FOldCustomer.Name else Result := Copy(FOldCustomer.Name,SpacePos+1,255); end; function TAdaptedCustomer.GetDOB: TDateTime; var FullYear: Word; begin if CustomerID > Last_OldCustomer_At_Year_2000 then FullYear := 2000 + FOldCustomer.DOB.Year else FullYear := 1900 + FOldCustomer.DOB.Year; Result := EncodeDate(FullYear, FOldCustomer.DOB.Month, FOldCustomer.DOB.Day); end; function GetCustomer(CustomerID: Longint): TNewCustomer; begin if CustomerID > Last_OldCustomer_In_Database then Result := TNewCustomer.Create(CustomerID) else Result := TAdaptedCustomer.Create(CustomerID) as TNewCustomer; end; end.
Java
class SquarePeg { private double width; public SquarePeg( double w ) { width = w; } public double getWidth() { return width; } public void setWidth( double w ) { width = w; } } /* The NEW */ class RoundHole { private int radius; public RoundHole( int r ) { radius = r; System.out.println( "RoundHole: max SquarePeg is " + r * Math.sqrt(2) ); } public int getRadius() { return radius; } } // Design a "wrapper" class that can "impedance match" the old to the new class SquarePegAdapter { // The adapter/wrapper class "has a" instance of the legacy class private SquarePeg sp; public SquarePegAdapter( double w ) { sp = new SquarePeg( w ); } // Identify the desired interface public void makeFit( RoundHole rh ) { // The adapter/wrapper class delegates to the legacy object double amount = sp.getWidth() - rh.getRadius() * Math.sqrt(2); System.out.println( "reducing SquarePeg " + sp.getWidth() + " by " + ((amount < 0) ? 0 : amount) + " amount" ); if (amount > 0) { sp.setWidth( sp.getWidth() - amount ); System.out.println( " width is now " + sp.getWidth() ); } } } class AdapterDemoSquarePeg { public static void main( String[] args ) { RoundHole rh = new RoundHole( 5 ); SquarePegAdapter spa; for (int i=6; i < 10; i++) { spa = new SquarePegAdapter( (double) i ); // The client uses (is coupled to) the new interface spa.makeFit( rh ); } } }
PHP
<?php class SimpleBook { private $author; private $title; function __construct($author_in, $title_in) { $this->author = $author_in; $this->title = $title_in; } function getAuthor() { return $this->author; } function getTitle() { return $this->title; } } class BookAdapter { private $book; function __construct(SimpleBook $book_in) { $this->book = $book_in; } function getAuthorAndTitle() { return $this->book->getTitle().' by '.$this->book->getAuthor(); } } // client writeln('BEGIN TESTING ADAPTER PATTERN'); writeln(''); $book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns"); $bookAdapter = new BookAdapter($book); writeln('Author and Title: '.$bookAdapter->getAuthorAndTitle()); writeln(''); writeln('END TESTING ADAPTER PATTERN'); function writeln($line_in) { echo $line_in."<br/>"; } ?>
Referências
- ↑ LASATERS,Christopher (2006). Design Patterns. wordware Applications Library 1 ed. [S.l.]: Jones & Bartlett Learning. ISBN 1598220314 Parâmetro desconhecido
|Autor=
ignorado (|autor=
) sugerido (ajuda) página 206 - ↑ GAMMA, Erich (2000). PADRÕES DE PROJETO. Soluções Reutilizaveis de Software Orientado a Objetos 1 ed. [S.l.]: Bookman. ISBN 0201633612 Parâmetro desconhecido
|Autor=
ignorado (|autor=
) sugerido (ajuda) página 70 - ↑ HORSTMANN, Cay David (2007). PADRÕES E PROJETO DE SOFTWARE ORIENTADOS A OBJETOS 2 ed. [S.l.]: Bookman. ISBN 9788560031511 Parâmetro desconhecido
|Autor=
ignorado (|autor=
) sugerido (ajuda); páginas 385 e 386 - ↑ FREEMAN, Eric (2007). Use a Cabeça!PADRÕES DE PROJETO. DESIGN PATTERNS 2 ed. [S.l.]: Alta Books. ISBN 9788576081746 Parâmetro desconhecido
|Autor=
ignorado (|autor=
) sugerido (ajuda)