miércoles, 27 de mayo de 2009

FLYWEIGHT

Nombre

Flyweight

Clasificación

Estructural

Intención

Uso compartido de objetos para soportar un gran número de objetos finos eficientemente.

Motivo


Algunas aplicaciones pueden usar objetos durante todo su diseño, pero esto puede ocasionar implementaciones costosas. La mayoría de editores de documentos tienen formato de texto y facilidades de edición que son implementados por alguna extensión. Típicamente editores de documento orientados a objetos usan objetos para representar elementos embebidos como tablas o figuras, así también utilizan objetos para representar cada carácter, manejar el editor de esta ma-nera ofrece flexibilidad al sistema, pues pue-den ser dibujados y formateados uniforme-mente, con figuras y tablas, pero la desventaja es que un documento de texto puede tener miles de caracteres, por eso te-ner un objeto por carácter implica un gran costo debido a la memoria que puede consumir. Flyweight permite compartir objetos ligeros, para hacer el programa más liviano. Los objetos pueden compartir estados intrínsecos que no dependen del contexto, pero no pueden compartir los estados extrínsecos que dependen del contexto.

Aplicabilidad


La efectividad de este patrón depende de cómo y cuándo es utilizado, por eso es im-portante implementarlo siempre que todas las siguientes situaciones se cumplan:
• Una aplicación usa un gran número de objetos.
• El coste de almacenamiento es alto de-bido al excesivo número de objetos.
• La gran mayoría de los estados de los objetos puede hacerse extrínseco.
• Al separar el estado extrínseco, muchos grupos de objetos pueden reemplazarse por unos pocos objetos compartidos.
• La aplicación no depende de la identi-dad de los objetos, pues el patrón se basa en el compartimento de objetos.

Estructura


Participantes

• Flyweight: Declara una interfaz por medio de la cual flyweights puede recibir e in-terpretar estados extrínsecos.
• ConcreteFlyweight: implementa la interfaz Flyweight y almacena estados intrín-secos, si existen. Los ConcreteFlyweight deben ser compartibles, cualquier estado de este debe ser intrínseco.
• UnsharedConcreteFlyweight: No todos los flyweight tienen que ser compartidos, la interfaz Flyweight habilita el comparti-miento pero no lo fuerza. Es común que los objetos UnsharedConcreteFlyweight tengan objetos ConcreteFlyweight como hijos en algún nivel de la estructura del flyweight.
• FlyweightFactory: Crea y maneja objetos flyweight, se asegura que flyweights se-an compartidos adecuadamente. Cuando el cliente hace la petición de flyweight la FlyweightFactory proporciona una ins-tancia existente, y si no existe crea una.
• Client: Mantiene una referencia a Fly-weight. Almacena o calcula los estados extrínsicos de los flyweights.

Colaboración

• Los estados que flyweights necesitan para funcionar, deben ser clasificados como intrínsecos o extrínsecos. Los estados intrínsecos se almacenan en ConcreteFlyweight, mientras los extrínsecos los conoce el cliente y los pasa como parámetros cuando llama operaciones de los flyweights.
• Los clientes no deben obtener estados directamente de ConcretFlyweight, sino por medio de FlyweightFactory, quien es que se asegura que los objetos sean compartidos adecuadamente.

Consecuencias

El patrón puede tornarse pesado en tiempo de ejecución por la cantidad de transferen-cias, cálculos y búsquedas de estados extrínsecos que pueda manejar maneja. Sin embargo, esto se contrarresta con el espacio de memoria que se salva como producto de los estados que se comparten. La ganancia en memoria depende de varios factores:
• La reducción del número total de instan-cias que son compartidas.
• La cantidad de estados intrínsecos por objeto.
• Si el estado extrínseco es calculado o almacenado.
Es conveniente que los estados extrínsecos se calculen y no se almacenen, pues esto genera un ahorro extra de memoria.El patrón se suele combinar con composite, para representar la estructura jerárquica co-mo un grafo con nodos y hojas como objetos compartidos.

Implementación

Considere los siguientes aspectos cuando implemente el patrón de diseño flyweight:
• Eliminar estados extrínsecos. El patrón depende ampliamente de identificar es-tados extrínsecos y removerlos de los objetos compartidos. Los estados extrín-secos, por su parte deben ser calcula-dos, en alguna parte donde los requeri-mientos de memoria sean bajos.
• Debido a que los flyweight son comparti-dos, no deberían ser instanciados direc-tamente por los clientes. La clase Fly-weightFactory deja a los clientes localizar un flyweight en particular.

Código ejemplo

El código ejemplo pinta 5 pelotas en la pantalla, pero solo utiliza un objeto que sirve de referencia a las 5 pelotas.

//Interfa Flyweight

import java.awt.Image;

public interface Pelota {

public Image getPelota();

}

//ConcreteFlyweight implementa la inerfaz y guarda estados intrínsecos

import java.awt.Image;

import java.awt.image.BufferedImage;

import java.io.IOException;

import javax.imageio.ImageIO;

public class PelotaConcreta implements Pelota {

private BufferedImage imagen;

public PelotaConcreta() {

try{

imagen= ImageIO.read(getClass().getClassLoader().getResource("pelota.gif"));

}catch(IOException e){

System.out.println("no se puede cargra la imagen");

}

}

public Image getPelota(){

System.out.println("aqui");

return (Image)imagen;

}

}

//(FlyweightFactory) garantiza que los objetos se inicialicen correctamente.

//Fijese que esta clase es un singleton.

public class PelotaFactory {

private static Pelota miPelota =null;

public static Pelota getPelota(){

if(miPelota==null)miPelota=new PelotaConcreta();

return miPelota;

}

}

//(Client) Mantiene una referencia a pelota

//almacen estados esxtrínsecos.

import java.awt.Image;

public class DibujaPelota {

private Pelota pelota = PelotaFactory.getPelota();

//Estados extrínsicos que son mantenidos por el cliente

private int cordX=0;

private int cordY=0;

public Image getPelota(){

return pelota.getPelota();

}

public void setCordX(int x){

cordX=x;

}

public void setCordY(int y){

cordY=y;

}

public int getCordX(){

return cordX;

}

public int getCordY(){

return cordY;

}

}

//clase que se encarga d la presentacion

import javax.swing.JPanel;

import javax.swing.JButton;

import javax.swing.JFrame;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.Image;

import java.awt.Graphics;

import java.util.Random;

public class Presentacion extends JFrame implements ActionListener{

private final int DIMENSION_IMAGEN =40;

private JPanel panel;

private JButton mover;

private Image imagen=null;

private DibujaPelota pelotas[]={new DibujaPelota(),new DibujaPelota(),new DibujaPelota(),new DibujaPelota(),new DibujaPelota()};

private DibujaPelota pelota=pelotas[0];

private int x=0;

private int y=0;

private Random aleatorio= new Random(1000L);

public Presentacion(){

panel = new JPanel();

mover=new JButton("Mover");

this.setTitle("Pelotas");

this.setSize(350,400);

this.setResizable(false);

this.setVisible(true);

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

panel=(JPanel)this.getContentPane();

panel.setLayout(null);

panel.add(mover);

mover.setBounds(20, 20, 70, 20);

mover.addActionListener(this);

//aleatorio.setSeed(1000);

}

public static void main(String args[]){

new Presentacion();

}

public void paint(Graphics g){

g.fill3DRect(100, 100, 20, 20, true);

g.clearRect(x,y+100,DIMENSION_IMAGEN,DIMENSION_IMAGEN);

imagen=pelota.getPelota();

g.drawImage(imagen,pelota.getCordX(),pelota.getCordY(),DIMENSION_IMAGEN,DIMENSION_IMAGEN,this);

}

public void actionPerformed(ActionEvent e) {

for(int i=0; i<5;>

x=pelotas[i].getCordX();

y=pelotas[i].getCordY();

pelotas[i].setCordX((int)aleatorio.nextLong()*240);

pelotas[i].setCordY((int)aleatorio.nextLong()*340);

pelota=pelotas[i];

}

repaint();

}

}



Usos conocidos

• El primer uso que se le dio al patrón fue en un poderoso editor de texto, de inter-views, llamado Doc.
• Et++ usa flyweight para soportar diferen-tes apariencias (look and feel).

Patrones relacionados


• AbstractFactory: El Flyweight factory es un Abstactfactory.
• Como se menciono anteriormente, Com-posite es combinado con este patrón pa-ra representar las jerarquías de herencia como un árbol con nodos y hojas que hacen el papel de objetos compartidos.
• Comúnmente es conveniente implemen-tar State y Strtegy son immolementados con Flyweight.

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.


5 comentarios:

Oscar Sandoval dijo...

buen post...te dejo mi blog http://www.oscar-sandoval.blogspot.com/

Mauricio García dijo...

ok , gracias, se hace lo que se puede, revisaré tu blog.

Anónimo dijo...

no me funcionó el ejemplo. Lo traté de adaptar al netbeans pero tira un error:
Exception in thread "main" java.lang.IllegalArgumentException: input == null!

Unknown dijo...

Hola! Esta muy excelente tu post..es muy interesante..ya ratos andaba en la web buscando una info de los patrones de diseño pero casi no entendia hasta que lei el tuyo..esta excelente!
Saludos

Javier ™ dijo...

Hola buena info, pero tengo una duda según entiendo es para crear elementos de 'usar y tirar', o sea, que no puedo crear elementos (por ejemplo líneas) y acceder luego a ellos para por ejemplo seleccionarlos haciendo click, ¿es así?

Gracias :)