sábado, 16 de mayo de 2009

ADAPTER

Nombre

Adapter.

Clasificación

Estructural.

Intención

Adapter adapta una interfaz existente a otra, permitiendo así, que dos interfaces trabajen conjuntamente, aunque estas sean incompatibles.

Motivo

Un toolkit está diseñado para ser reutilizado, pero el problema es que su interfaz no es compatible con la que cierta aplicación requiere y por este motivo no puede ser reutilizada.

Por ejemplo, pensemos en un editor gráfico que deja al usuario dibujar y organizar elementos gráficos (polígonos, líneas, flechas, etc.) dentro de dibujos o diagramas. La abstracción clave del editor es la del objeto gráfico que permite dibujarse a él mismo. La interfaz para los objetos es una clase abstracta y de esta hereda una subclase por cada figura como línea, polígono, etc.

Si pensamos en las subclases línea y polígono, son fáciles de implementar, pues sus características (dibujar, editar) son heredables de la clase abstracta, pero si nuestro editor incluye una clase que maneja texto (lo muestra y edita), la cosa es más compleja, porque esta subclase no es tan compatible con la clase abstracta padre, debido a que un editor de texto debe manejar refrescos de pantalla, y un gestor de memoria temporal (buffer). Ahora supongamos que en un toolkit, tenemos una subclase visorTexto que hace todo lo que necesitamos pero el problema es que esta clase (visorTexto) no es compatible con nuestro editor gráfico, la pregunta que surge es ¿cómo podemos utilizar esta clase en nuestro editor gráfico?; la respuesta es utilizando el patrón adapter que se encarga de adaptar la clase ya existente a nuestro editor gráfico.

Aplicabilidad

Adapter debe ser usado cuando:
• Una clase existente y su interfaz no coincide con la que se necesita.
• Se desea crear una clase reutilizable que debe colaborar con clases no relacionadas o imprevistas.
• Se necesita adaptar un número considerable de clases existentes, pero es impráctico adaptar la interface, de cada subclase. Un adapter con composisción puede adptar la interfaz padre.

EstructuraParticipantes

• Target: Define el dominio específico que la interfaz usa.
• Client: Requiere de objetos que de la interfaz target.
• Adaptee: Define una interfaz existente, que necesita ser adaptada.
• Adapter: Adapta la interfaz de adaptee, a la interfaz de target.

Colaboración

Cliente llama operaciones sobre una instancia de adapter y luego este llama a adaptee para encargarse de la petición de cliente.

Consecuencias

• Deja a un único adapter trabajar con muchos adaptee, al adpate mismo y a sus subclases.
• Es difícil sobrescribir el comportamiento de adaptee, con una adaptador por composición a diferencia de un adaptador por herencia.
• e una sóla vez.

Implementación

Crear una nueva clase que será el Adaptador, que extienda del componente existente e implemente la interfaz obligatoria. De este modo tenemos la funcionalidad que queríamos y cumplimos la condición de implementar la interfaz.La diferencia entre los patrones Adapter y Facade, es que el primero reutiliza unainterfaz ya existente, mientras que el segundo define una nueva con el objetivode simplificarla.

Código ejemplo

El código ejemplo muestra diferentes figuras; en él se supone la existencia de figuras de un tipo cuya interfaz se denomina figuras1 y a esta interfaz se adapta otra denomina figuras2 que contiene otro tipo de figuras.

//interfaz Figura2 (Target)

import java.awt.Graphics;

public interface Figuras2 {

public String getFigura();

public double area();

public double perimetro();

public void dibujarFigura(Graphics g);

}

//Clase cuadrado que hereda de interfaz figura2

import java.awt.Color;

import java.awt.Graphics;

public class Cuadrado implements Figuras1{

private int lado=2;

public Cuadrado(int a){

if(a>100)a=100;

lado=a;

}

public int area() {

return (lado*lado);

}

public String informacion() {

return "Este es un Cuadrado";

}

public int lados() {

return 4;

}

public int perimetro() {

return 4*lado;

}

public void pintar(Graphics g) {

g.setColor(Color.BLACK);

g.fillRect(100,180, lado, lado);

}

}

//clase Adaptador que hereda de Figuras2 y tiene una instancia de Figura1 como atributo(Adapter)

import java.awt.Graphics;

public class Adaptador implements Figuras2{

private Figuras1 fig;

public Adaptador(Figuras1 f){

fig=f;

}

public double area() {

return fig.area();

}

public void dibujarFigura(Graphics g) {

fig.pintar(g);

}

public String getFigura() {

return fig.informacion();

}

public double perimetro() {

return fig.perimetro();

}

}

// Interfaz Figuras1 (Adaptee)

import java.awt.Graphics;

public interface Figuras1 {

public String informacion();

public int lados();

public int area();

public int perimetro();

public void pintar(Graphics g);

}

//clase Circulo que hereda de inetrfaz Figura1

//esta es la clase que se reutiliza.

import java.awt.Color;

import java.awt.Graphics;

public class Circulo implements Figuras2 {

private int radio=3;

public Circulo(int r){

if(r>50)r=50;

radio=r;

}

public double area() {

return radio*radio*3.16;

}

public void dibujarFigura(Graphics g) {

g.setColor(Color.BLUE);

g.fillOval(100, 180, (2*radio), (2*radio));

}

public String getFigura() {

return "Este es un Circulo";

}

public double perimetro() {

return 2*radio*3.16;

}

}

//cliente que utiliza la interfaz Figura2 (Client)

import javax.swing.*;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.Color;

import java.awt.Graphics;

public class Presentacion extends JFrame implements ActionListener{

private JPanel panel;

private JButton figura1;

private JButton figura2;

private Circulo circulo = new Circulo(50);;

private Cuadrado cuadro = new Cuadrado(100);

private Adaptador adaptador = new Adaptador(cuadro);

private Figuras2 figura = circulo;

public Presentacion(){

panel = new JPanel();

figura1= new JButton("Figura 1");

figura2=new JButton("Figura 2");

this.setTitle("Figuras");

this.setSize(300,300);

this.setResizable(false);

this.setVisible(true);

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

panel=(JPanel)this.getContentPane();

panel.setLayout(null);

panel.add(figura1);

panel.add(figura2);

figura1.setBounds(20, 20, 100, 30);

figura2.setBounds(160, 20, 100, 30);

figura1.addActionListener(this);

figura2.addActionListener(this);

}

public static void main(String args[]){

new Presentacion();

}

public void paint(Graphics g){

g.setColor(Color.white);

g.fillRect(0, 100,300 ,200);

g.setColor(Color.BLACK);

g.drawString(figura.getFigura(),20, 120);

g.drawString("Area: "+figura.area(), 20, 140);

g.drawString("Perimetro:"+figura.perimetro(),20, 160);

figura.dibujarFigura(g);

}

public void actionPerformed(ActionEvent e) {

if(e.getSource()==figura1){

figura=circulo;

}

if(e.getSource()==figura2){

figura=adaptador;

}

repaint();

}

}



Usos conocidos

• Editor gráfico ET++draw, que usa la clase de gestión de texto de ET++.
• Interview 2.6 maneja adapter para usar inter-faces para los botones, los scroolbar y menús.

Patrones relacionados

• Bridge tiene una estructura similar pewro su intención es diferente. El patrón bridge separa la abstracción de la implementación de un componente, permitiendo que sean modifica-dos independientemente, mientras adapter reutiliza un componente ya existente que no es compatible.
• Decorator adiciona funcionalidad a la interfaz una objeto, adpater modifica la interfaz pero no cambia su funcionalidad.
• Proxy al igual que adapter define una interfaz para un objeto pero no cambia su interfaz.

Referencias bibliográficas
[1] Erich Gamma et al, Elements of reusable object-oriented software.
[2] Steve Holzner, Design patterns for dummies, Wiley Publishing Inc, Indianapolis, EEUU, 2006, 339.
[3] Jesús García Molina, Análisis y diseño de software - Patrones de diseño, dis.um.es/~jmolina/astema3.

No hay comentarios: