sábado, 23 de abril de 2016

Patrones de Diseño Estructurales Parte 3


11. Flyweight: Permite gestionar eficientemente un gran números de objetos pequeños compartiendo objetos más generales. Comparte el apoyo a un gran número de objetos de grano fino de manera eficiente. El patrón flyweight describe como almacenar un gran número de objetos sin un gran costo.
Para conseguir esto se utlizan objetos que almacenan los estados compartidos y que pueden ser usados por varios objetos simultáneamente. Un flyweight es un objeto compartido que se puede utilizar en varios contextos al mismo tiempo. El flyweight actúa como un objeto independiente en cada contexto. Es indistinguible para una instancia del objeto que no es compartida. Flyweight no puede hacer suposiciones sobre el contexto en el que lo operan. El concepto clave aquí se distinguen entre estado intrínseco y extrínseco. El estado intrínseco es almacenado en flyweight; y consiste en información que es independiente del contexto de flyweight; haciendo esto compatible. El estado extrínseco depende y varía con el contexto de flyweight, y por tanto no puede ser compartido. Los objetos del cliente son responsables del paso a estado extrínseco de flyweight cuando este lo necesita. La eficacia del patrón Flyweight depende en gran medida de cómo y dónde se utiliza. Aplicamos el patrón Flyweight cuando una aplicación usa un gran número de objetos, los costos de almacenamiento son altos debido al gran número de objetos, la mayoria de objetos pueden hacerse en estado extrínseco, muchos grupos de objetos se puede sustituir por un número reducido de objetos compartidos, una vez que se elimina el estado extrínseco, la aplicación no depende de la identidad de los objetos.

Diagrama UML

Ejemplo

Un programa que  obtiene el círculo de color deseado que se necesita aplicando este patrón.

Crea una interface
public interface Shape {
   void draw();
}
 Crear clases implentado las mismas interfaces.

public class Circle implements Shape {
   private String color;
   private int x;
   private int y;
   private int radius;

   public Circle(String color){
      this.color = color;      
   }

   public void setX(int x) {
      this.x = x;
   }

   public void setY(int y) {
      this.y = y;
   }

   public void setRadius(int radius) {
      this.radius = radius;
   }

   @Override
   public void draw() {
      System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + 
       ", y :" + y + ", radius :" + radius);
   }
}
Crear los factores  a generar objetos de clases concretas basado en información dada.

import java.util.HashMap;

public class ShapeFactory {
   private static final HashMap<String, Shape> circleMap = new HashMap();

   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);

      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
}

Usa los factores a obtener objetos de clases concretas para pasar información  tal como color.

public class FlyweightPatternDemo {
   private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" };
   public static void main(String[] args) {

      for(int i=0; i < 20; ++i) {
         Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor());
         circle.setX(getRandomX());
         circle.setY(getRandomY());
         circle.setRadius(100);
         circle.draw();
      }
   }
   private static String getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   private static int getRandomX() {
      return (int)(Math.random()*100 );
   }
   private static int getRandomY() {
      return (int)(Math.random()*100);
   }
}

11. Proxy: Juega como un intermediario que permite la creación y acceso de un objeto a otros, es decir me sirve como un puente entre objetos, su aplicación más común es el uso de proxies en internet para acceder a páginas o para limitar el tráfico a las mismas. Provee un sustituto de un objeto para controlar el acceso a un objeto. Controlar el acceso a un objeto, puede tener muchas razones, como hacer carga de objetos por demanda para postergar la carga completa del mismo hasta que sea totalmente necesario, por lo general se hace esto cuando final demandado es bastante pesado(por ejemplo imágenes de gran tamaño), otra razón es la protección del objeto, de modo que se pueden hacer validaciones u operaciones necesarias antes de usar el método real del objeto final. Este patrón se usa simpre que se quiera usar como un intermediario para manejar adecuadamente el objeto final, algunas situaciones en las cuales debe aplicarse este patrón cuando es proxy remoto es donde se desea representar un objeto remoto como local, por ejemplo en el uso de librerías externas y en web services, proxy virtual es donde se desea crear objetos pesados por demanda, por ejemplo en la carga de imágenes y  el proxy protector donde se desea controlar el acceso a un objeto, por ejemplo en un login o registro de usuario para filtrar los datos que se envía y quitar cualquier inyección sql u  algunas otra porción de código malicioso o también para la implementación de un ACL entra el cliente y la clase final requerida. El uso de proxies dinámicos permite la ejecución de tareas avanzadas en frameworks de gran coomplejidad como Hibernate o Spring AOP.

Diagrama UML


Ejemplo

En Java es fácil crear proxies dinámicos en tiempo de ejecución a partir de la clase java.lang.reflect.Proxy.
Creamos una interfaz

package com.roldan.proxy;

public interface Lector {
 public void leer();
}
 Ahora creamos una implementación para esta interfaz:
package com.roldan.proxy;

public class LectorImpl implements Lector {

 public void leer(){
  System.out.println("Estamos leyendo...");
 }
}
En este momento, creamos el proxy para la clase LectorImpl:

package com.roldan.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class LectorProxy
 implements java.lang.reflect.InvocationHandler {

 private Object obj;
 
 public static Object newInstance(Object obj) {
  return java.lang.reflect.Proxy.newProxyInstance(
   obj.getClass().getClassLoader(),
   obj.getClass().getInterfaces(),
   new LectorProxy(obj));
 }

 private LectorProxy(Object obj) {
  this.obj = obj;
 }

 public Object invoke(
  Object proxy,
  Method m,
  Object[] args) throws Throwable {
  Object result;
  try {
   System.out.println(
    "Antes de llamar al metodo " + m.getName());
   result = m.invoke(obj, args);
  } catch (InvocationTargetException e) {
   throw e.getTargetException();
  } catch (Exception e) {
   throw new RuntimeException(e.getMessage());
  } finally {
   System.out.println(
    "Despues de llamar al metodo " + m.getName());
  }
  return result;
 }
}

 Ahora podemos crear una instancia de este proxy y acceder a los métodos de la interfaz Lector que implementa:

package com.roldan.proxy;

public class PruebaLector {
 public static void main(String[] args) {
  Lector lector = (Lector)LectorProxy.newInstance(
   new LectorImpl());
  lector.leer();
 }
}

No hay comentarios:

Publicar un comentario