martes, 22 de octubre de 2013

PATRÓN BRIDGE


Clasificación:
Patrón Estructural. 

Propósito:
Separa abstracción e implementación, así ambas pueden variar de forma independiente.  A diferencia del patrón Adapter, considera como las interfaces son implementadas, en este sentido asocia abstracción y sus potenciales implementaciones. Suele aplicarse al empezar un diseño, para permitir que las abstracciones e implementaciones evolucionen independientemente.

También Conocido como:
Puente / Cuerpo.
Intención:

Desacopla una abstracción de su implementación de modo que ambos puedan cambiar independientemente.

Motivacion:
La herencia permite que una abstracción tenga varias implementaciones: esta relación se define en tiempo de compilación.  Una clase abstracta define la interfaz a la abstracción y la aplicación de las subclases concretas en diferentes maneras.  Sin embargo,  no siempre es lo suficientemente flexible, obligando a una  aplicación de herencia  para la captación permanente, por lo que resulta difícil de modificar, ampliar, y la reutilización de abstracciones e implementaciones independiente. 

Aplicabilidad:
Se utiliza el patrón cuandose desea evitar una permanente vinculacion  entre una abstracción y su aplicación. Este podría ser el caso, por ejemplo, cuando la aplicación  debe seleccionar o cambiar en tiempo de ejecución.  Tanto las abstracciones y sus implementaciones deben ser extensibles por las subclases. En este caso, el patrón de Bridge  permite combinar las diferentes abstracciones e implementaciones y ampliar de forma independiente-, de modo que los cambios en las clases abstractas existentes no deben influir en la aplicación , tal modo se comparte una implementación entre múltiples objetos, sin que lo noten los clientes.

Estructura:
La estructura de un Bridge se puede clasificar en  dos partes: la parte abstracta y la implementacion  de la interfaz por  las diferentes clases del grupo de objetos, de  modos que la relación se hace mediante una agregacion de la interfaz por partde de la clase abstracta, de esta forma se relaciona la primer parte y la segunda, donde sus comportamientos son independientes.


Los participantes:

Abstraction: 
  • Define la abstracción de la interfaz, manteniedo  una referencia a un objeto que implementa la interfaz. 
RefinedAbstraction:
  • Amplía la interfaz definida por la abstracción, de modo que captura las especificaciones o información necesaria proveniente del objeto que implementa la interfaz. 
Implementor:
  • Define la interfaz de la aplicación clases. Esta interfaz no tiene que corresponder exactamente a la interfaz de abstracción, de  hecho  las dos interfaces pueden ser muy diferentes. Normalmente  la interfaz  Implementor proporciona sólo operaciones primitivas, y define la abstracción de alto nivel sobre la base de estas operaciones primitivas. 
ConcreteImplementor:
  • Implementa la interfaz concreta y define sus aplicació
Client:
  • Utiliza los objetos proporcianados por sus gusto.
Colaboraciones:
Abstracción remite las solicitudes de los clientes a su ejecutor objeto, desacoplando la  interfaz e implementación. así ésta  no se vincula permanentemente a la interfaz, y se puede determinar en tiempo de ejecución (incluso cambiar). – Se eliminan dependencias de compilación, consiguiendo una arquitectura más estructurada en niveles mejorando la extensibilidad donde las jerarquías de abstracción y de implementación pueden evolucionar independientemente.

Consecuencias:
  1. La disocia la interfaz  de la aplicación. Una aplicación no está vinculada permanente a una interfaz.  Es incluso posible que un objeto pueda cambiar su aplicación en tiempo de ejecución.   La Abstracción y la interfaz eliminan tiempo de compilación y dependencias de la aplicación, de modo que el cambio de una  clase no requiere recompilar la clase de abstracción y de sus clientes.  Esta propiedad es esencial cuando se debe garantizar la compatibilidad binaria entre diferentes versiones de una biblioteca de clases. Por otra parte, esta disociación alienta capas que pueden conducir a una mejor sistema estructurado.  
  2. Mejora de la extensibilidad, de forma que se puede ampliar la Abstracción y ejecutor en  jerarquías independientes. 
  3. Oculta detalles de implementación a los clientes, protegiendo detalles de implementación, como el intercambio de objetos y el mecanismo de acompañamiento de referencias (en su caso). 
Implementación:
En el siguiente ejemplo, se lleva a cavo la solicitud de un pedido en una panadería, donde el cliente elige el diferente tipo de pan que hay disponible.

//nuestra clase Abstraction, su método permite obtener el tipo de pan del pedido//
package Logica;
public abstract class Panaderia {                 
            public abstract TipoDePan getImplementador();
            public abstract String nombrePan();
}
//*Ahora creamos una clase que hereda de Panaderia, en la cual se estructura el metodo de la clase abstracta y se crean nuevos metodos, los cuales trabajan con un objeto de la que implementa la interfaz*//
package Logica;
public class Panes extends Panaderia {
 private TipoDePan pan;

 public String nombrePan() {
  return pan.tipoPan();
 }
 public void setInterfaz(TipoDePan tipoInterfaz) {
  pan = tipoInterfaz; 
 }
 public TipoDePan getImplementador() {
  return pan;
 }
}
// Creamos la interfaz//
package Logica;
public interface TipoDePan {
 public abstract String  tipoPan();
}
//*Ahora se crean las clases de los diferentes tipos de pan disponibles sobreescribiendo el método implementado de la interfaz*//
package Logica;
public class PanDeFrutas implements TipoDePan {
 public String tipoPan() {
  return "Pan de Frutas";
 }
}
package Logica;
public class PanIntegral implements TipoDePan {
 public String tipoPan() {
  return "Pan integral";
 }
}

package Logica;
public class PanLight implements TipoDePan {
 public String tipoPan() {
  return "Pan Light";
 }
}
Por último tenemos la vantana donde el cliente podra seleccionar y obtener su pedido:
package Interfaz;
import Logica.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Pedido extends JFrame implements ActionListener {
//atributos de la clase//
 Panaderia panaderia ;
 private JButton panIntegral;
 private JButton panLight;
 private JButton panDeFrutas;
 private JLabel suOrden;
 //constructor de la clase, e inicializamos y ubicamos los atributos//
 public Pedido(){
 this.setSize(400,300); 
        this.setLayout(null);
        this.setDefaultCloseOperation(Pedido.DISPOSE_ON_CLOSE);
        this.setTitle(":::Panaderia:::");
                
 suOrden = new JLabel();
 suOrden.setSize(300,100);
 suOrden.setLocation(30, 20);
 suOrden.setText("Seleccione su Pan :");
        this.getContentPane().add(suOrden);
        
 panIntegral = new JButton();
 panIntegral.setSize(110, 30);
 panIntegral.setLocation(10, 100);
 panIntegral.setText("pan Integral");
        this.getContentPane().add(panIntegral);
        panIntegral.addActionListener(this);
        panLight = new JButton();
        panLight.setSize(110, 30);
        panLight.setLocation(130, 100);
        panLight.setText("pan Light");
        this.getContentPane().add(panLight);
        panLight.addActionListener(this);
        panDeFrutas = new JButton();
        panDeFrutas.setSize(120, 30);
        panDeFrutas.setLocation(250, 100);
        panDeFrutas.setText("pan De Frutas");
        this.getContentPane().add(panDeFrutas);
        panDeFrutas.addActionListener(this);
 }

 //manupula el objeto segun la especificacion del cliente//
 @Override
 public void actionPerformed(ActionEvent e) {
//inicializa un objeto de la clase Panes//
        Panes pan= new Panes();
  if (e.getSource() == panDeFrutas) {
//reliza la implemntacion pasando en su método el tipo de pan que se eligió//
   pan.setInterfaz(new PanDeFrutas());
        }
        if (e.getSource() == panLight) {
         pan.setInterfaz(new PanLight());   
        }
        if (e.getSource() == panIntegral) {
         pan.setInterfaz(new PanIntegral());
        }
//se presenta al cliente el pedido como tal//
        suOrden.setLocation(100, 130);
        suOrden.setText("Su orden es : " + pan.nombrePan());
 }
}

Usos conocidos:
Las clases Button y MenuItem 
de Java facilitan la utilización de este patrón, declaran los métodos getActionCommand y setActionCommand para dar nombres a las acciones realizadas por los objetos, facilitándose una correspondencia entre ambos.

Patrones  Relacionados:
  • Abstract Factory permite crear y configurar un Bridge particular (y esta factoría puede ser un Singleton).
  •  El patrón Adaptador tiene también el objetivo de hacer trabajar juntas clases con distinta interfaz, pero en general se aplica a sistemas que ya existen. El patrón Bridge suele aplicarse al empezar un diseño, para permitir que las abstracciones e implementaciones evolucionen independientemente.
Referencias:

PDF-Departamento de Sistemas Informáticos y Programación Curso de doctorado 1999 -2000 Patrones de  diseño orientado a objetos.
 DesIgn Patterns: Elements of Reusable Object-Oriented Software Gamma, Helm, Johnson,  Vlissides Editorial  Addison-Wesley.

PATRÓN ADAPTER (ADAPTADOR)





Clasificación:
Patrón  Estructural.

Propósito:
Convertir la interfase de una clase en otra interfase que el cliente espera.  El adapter permite que clases trabajen juntas, mediante la sobreescritura de los métodos de las clases padre e implementada por el objeto adaptado, que de otra manera no podrian por las interfaces incompatibles.

También conocido como:
Wrapper.
Intención:

Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda. Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles 

Motivación :
Este patrón se centra en resolver incompatibilidades entre dos interfaces existentes. Se utiliza para hacer funcionar las cosas después de que estas han sido diseñadas.

Aplicabilidad:
Se utiliza el  patrón Adapter cuando se desea utilizar una clase existente, y su interfaz no coincide con  una que usted necesita. Debe crear una clase reutilizable que coopere con o sin relación  de clases, es decir, clases que no tienen necesariamente interfaces compatibles .

Estructura :
La estructura de un class Adapter usa  herencia de una clase, e implementación de una interfaz  para adaptar un objeto que posea características de ambos.

 
Participantes:
  • Target
    • Define el dominio de la interfaz que el Cliente usa.
  • Cliente
    • Colabora con los objetos conformando la interfaz del  Target.
  • Adaptee (el adaptado)
    • Define la interfaz existente que necesita adaptación.
  • Adapter
    • Adapta la interfase Adaptee para usar en el objeto de Target.
Colaboraciones :
El Cliente llama a las operaciones en la instancia del Adapter.  Luego, el Adapter llama alAdaptee (el Adaptado) y lleva a cabo las operaciones pedidas

Object Adapter: 
El object adapter  adapta las clases, no instancias u objetos. Esto puede traer problemas a la hora de instanciar esas clases adaptadas ya que puede ocurrir que el objeto que se  tiene no sea lo que se necesita. En caso de que se necesite, ha de  saberse que objetos hay que adaptar cuando son llamados por el cliente,  o mejor dicho cuando ni bien se realice la “adaptación” se  puede usar una pequeña variante del Adapter, llamado Object Adapter
El object adapter trabaja creando una clase Adapter que solamente implemente la interfaz y contiene una instancia de la clase, o sea, un objeto a adaptar. No es necesario heredar la clase a adaptar porque en realidad se va  a trabajar con una instancia de esta.           

Cuándo emplearlo:
·     Se quiere usar una clase existente, y su interfaz no concuerda con la que se necesita.
·     Se quiere crear una clase reusable que coopere con clases no relacionadas o imprevistas, esto es,  clases que no tienen interfases compatibles necesariamente.
·     (object adapter solamente) necesita usar varias subclases existentes, pero no es practico adaptar sus interfases haciendo “subclassing” por cada una. Un object adapter puede adaptar la interfaz de sus clase padre (parent).

Consecuencias :
     Class Adapter 
·     Adapta el Adaptee al Target informando a un class Adapter concreto. Comoconsecuencia, un class Adapter no funciona cuando se quiere adaptar una clase y todas sus subclases (subclassing).
·    El Adapter sobreescribe el comportamiento del Adaptee ya que el Adapter es una subclase del Adapteee .
·     Introduce solamente un objeto y no hay un  puntero adicional para conseguir el Adaptee.
Object Adapter 
·      Un Adapter puede trabajar con multiples Adaptees, esto es, el Adaptee en si y todas sus subclases.
·     Hace más dificil de sobreescribir el comportamiento del Adpatee. Requerirá hacer subclasssing del Adaptee y hacer que el Adapter se remita a las subclases en vez delAdaptee en si.

Implementación :
El siguiente ejemplo ilustra  el patrón Adapter, el ejemplo trata de una  tienda de tortas, donde el usuario puede elegir una torta normal y/o agregarle algunas especificaciones disponibles, como lo son diferentes sabores de cubiertas para la decoración. 

Creamos la interfaz que permite adicionar características adicionales al objeto.
package logica;
//es nuestra clase Adaptee//
public interface Adaptee {    //*la interfaz Adaptee permite adicionar a la torta 
      public void decorar();   // diferentes características *//
      public voidcubiertaFresa();
      public voidcubiertaNaranja();
      public voidcubiertaCaramelo();
      public voidcubiertaChocolate();
}
Ahora la clase que  adapta el objeto al la interfaz; permitiendo combinar las características de ambas.
package logica;
//nuestra clase Adapter//
public class Adapter extendsTorta implements Adaptee{    
         //*esta clase es la adaptadora, donde el objeto creado
       //hereda de torta y puede tener caracteriaticas 
      // especiales dadas por la interfaz Adaptee*//
 String Cubierta;
 String FiguraEspecial;
      public Adapter(){  //constructor de la clase//
            Cubierta="Sin Cubierta";
            FiguraEspecial="";
      }   
  //obtiene un String con el nombre del sabor de la cubierta//
      public String getCubierta(){  
            return this.Cubierta;   
      }    
//obtiene un String que dice si el objeto posee una figura decorativa//
      public String getDecoracion(){  
            returnthis.FiguraEspecial; 
      }    
      @Override
// metodo de la interfaz; asigna el nombre del sabor de la cubierta//
      public voidcubiertaChocolate() { 
            Cubierta="Con Cubierta de Chocolate";              } 
      @Override
      public voidcubiertaFresa() {
            Cubierta="Con Cubierta de Fresa";       
      }
      @Override
      public voidcubiertaNaranja() {
            Cubierta="Con Cubierta de Naranja";     
      }
      @Override
      public voidcubiertaCaramelo() {
            Cubierta="Con Cubierta de Caramelo";          
      }
      @Override
//es un metodo de la interfaz//
      public void decorar() { 
//asigna una figura decorativa al objeto//
           FiguraEspecial="Decorada Con Figura Especial";      
      }    
      @Override
//retorna la descripcion la cubierta de la torta//
    public String pedidoCubierta(){
            return "Su pedido esta listo: **TORTA **\n"+this.getCubierta();
      }
      @Override
//retorna la descripcion de la decoración//
      public String pedidoDecoracion() {
            returnthis.getDecoracion();      
      }
}
Esta es la clase principal la cual debe ser abstracta, permitiendo de este modo tener métodos abstractos, que serán comunes simpre a cualquier pedido. 
package logica;
//nuestra clase Target//
//*clase principal a la que siempre pertenecerá el objeto creado la cual posee metodos abstractos//
public abstract class Torta {
      public abstract String pedidoCubierta();
      public abstract String pedidoDecoracion();
}
Por último, creamos la interfaz la cual presenta una ventana que permite al cliente elegir las características de la torta.
package intefaz;
import logica.*; 
import java.awt.event.*;
import javax.swing.*;
 //interfaz para la toma del pedido//
public class OrdenPasteleria extends JFrame implements ActionListener {
            Adapter torta;    
            private JButton figuraDecorativa; 
            private JButton cubiertaFresa;
            private JButton cubiertaCaramelo;
            private JButton cubiertaChocolate;
            private JButton cubiertaNaranja;
            private JTextArea suOrden;
            private JLabel orden;
           //constructor: inicializa y localizan los atributos//
            public OrdenPasteleria(){   
            this.setSize(400,300);               
            this.setLayout(null);
            this.setDefaultCloseOperation(OrdenPasteleria.DISPOSE_ON_CLOSE);
            this.setTitle(":;;Pasteleria UD:::");
       
            torta= new Adapter();       
            orden = new JLabel();
            orden.setSize(350,20);
            orden.setLocation(20, 20);
            orden.setText("Seleccione las características de su Torta ");
            this.getContentPane().add(orden);       
            suOrden = new JTextArea();
            suOrden.setSize(350,50);
            suOrden.setLocation(20, 200);
            suOrden.setText("Usted tiene una Torta " + torta.getCubierta());
            this.getContentPane().add(suOrden);
            suOrden.setEditable(false);    
           figuraDecorativa = new JButton();
           figuraDecorativa.setSize(150, 25);
           figuraDecorativa.setLocation(100, 150);
           figuraDecorativa.setText("Figura Especial");
           this.getContentPane().add(figuraDecorativa);
           figuraDecorativa.addActionListener(this);  
           cubiertaFresa = new JButton();
           cubiertaFresa.setSize(170, 30);
           cubiertaFresa.setLocation(20, 50);
           cubiertaFresa.setText("Cubierta de Fresa");
           this.getContentPane().add(cubiertaFresa);
           cubiertaFresa.addActionListener(this); 
           cubiertaCaramelo = new JButton();
           cubiertaCaramelo.setSize(170, 30);
           cubiertaCaramelo.setLocation(200, 50);
           cubiertaCaramelo.setText("Cubierta de Caramelo");
           this.getContentPane().add(cubiertaCaramelo);
           cubiertaCaramelo.addActionListener(this);        
           cubiertaChocolate = new JButton();
           cubiertaChocolate.setSize(170, 30);
           cubiertaChocolate.setLocation(20, 100);
           cubiertaChocolate.setText("Cubierta de Chocolate");
           this.getContentPane().add(cubiertaChocolate);
           cubiertaChocolate.addActionListener(this);       
           cubiertaNaranja = new JButton();
           cubiertaNaranja.setSize(170, 30);
           cubiertaNaranja.setLocation(200, 100);
           cubiertaNaranja.setText("Cubierta de Naranja");
           this.getContentPane().add(cubiertaNaranja);
           cubiertaNaranja.addActionListener(this);
       }         
      @Override
 //modifica  el objeto a peticion del cliente//
      public void actionPerformed(ActionEvent e) {          
           if (e.getSource() == figuraDecorativa) { 
               torta.decorar();
           }
          if (e.getSource() == cubiertaFresa){
             torta.cubiertaFresa();
           }
         if (e.getSource() == cubiertaCaramelo) {
           torta.cubiertaCaramelo();
          }
         if (e.getSource() == cubiertaChocolate) {
           torta.cubiertaChocolate();
         }
        if (e.getSource() == cubiertaNaranja) {
            torta.cubiertaNaranja();
        }
        suOrden.setSize(350,50);
        suOrden.setLocation(20, 200);
       //muestra el pedido como tal, las características de la torta//
       suOrden.setText(torta.pedidoCubierta()+'\n'+torta.pedidoDecoracion());
    
}
Usos conocidos:
Clases adaptadoras del JDK
  • Para gestionar eventos un objeto debe implementar EventListener
  • Para gestionar eventos de objetos de tipo Windowdebe implementar la interfaz WindowListenerque extiende EventListener
  • WindowListenertiene siete métodos, pero en muchas ocasiones sólo no se usan más de tres. 
  • El JDK proporciona la clase abstracta WindowAdapterpara dicho fin.    
Patrones relacionados : 
·       Bridge : Tiene una estructura similar alAdapter, pero un intento diferente : Su proposito es separar la interfase de su implementación asi esta puede variar facilmente y de forma independiente. El proposito del Adapter es el cambio de interfase de un objeto existente.

·      Decorator : Agrega resonsabilidades a un objeto dinamicamente sin cambiar su interfase .
Un Decorator en cambio es mas transparente a la aplicación que un Adapter, como consecuencia
Soporta composición recursiva,  lo cual no es posible con el patronAdapter.

·         Proxy : Define un lugar para otro objeto para controlar el acceso y no cambia su interfase.

REFERENCIAS: 

Design Patterns: Elements of Reusable Object-Oriented Software
Gamma, Helm, Johnson, Vlissides
Editorial Addison-Wesley