Prototype (patrón de diseño)
El patrón de diseño Prototype (Prototipo), tiene como finalidad crear
nuevos objetos duplicándolos, clonando una instancia creada previamente.
Este patrón especifica la clase de objetos a crear mediante la clonación
de un prototipo que es una instancia ya creada. La clase de los objetos que
servirán de prototipo deberá incluir en su interfaz la manera de solicitar una
copia, que será desarrollada luego por las clases concretas de prototipos.
Motivación
Este patrón resulta útil en escenarios donde es preciso abstraer la
lógica que decide qué tipos de objetos utilizará una aplicación, de la lógica
que luego usarán esos objetos en su ejecución. Los motivos de esta separación
pueden ser variados, por ejemplo, puede ser que la aplicación deba basarse en
alguna configuración o parámetro en tiempo de ejecución para decidir el tipo de
objetos que se debe crear. En ese caso, la aplicación necesitará crear nuevos
objetos a partir de modelos. Estos modelos, o prototipos, son clonados y el
nuevo objeto será una copia exacta de los mismos, con el mismo estado. Como
decimos, esto resulta interesante para crear, en tiempo de ejecución, copias de
objetos concretos inicialmente fijados, o también cuando sólo existe un número
pequeño de combinaciones diferentes de estado para las instancias de una clase.
Dicho de otro modo, este patrón propone la creación de distintas
variantes de objetos que nuestra aplicación necesite, en el momento y contexto
adecuado. Toda la lógica necesaria para la decisión sobre el tipo de objetos
que usará la aplicación en su ejecución se hace independiente, de manera que el
código que utiliza estos objetos solicitará una copia del objeto que necesite.
En este contexto, una copia significa otra instancia del objeto. El único
requisito que debe cumplir este objeto es suministrar la funcionalidad de
clonarse.
En el caso, por ejemplo, de un editor gráfico, podemos crear
rectángulos, círculos, etc. como copias de prototipos. Estos objetos gráficos
pertenecerán a una jerarquía cuyas clases derivadas implementarán el mecanismo
de clonación.
Estructura
En la imagen podemos ver la estructura del patrón:
Participantes
Cliente: Es el encargado de
solicitar la creación de los nuevos objetos a partir de los prototipos.
Prototipo Concreto: Posee una
características concretas que serán reproducidas para nuevos objetos e
implementa una operación para clonarse.
Prototipo: Declara una
interfaz para clonarse, a la que accede el cliente.
Colaboraciones
El cliente solicita al prototipo que se clone.
Consecuencias
Aplicar el patrón prototipo permite ocultar las clases producto
(prototipos concretos) del cliente y permite que el cliente trabaje con estas
clases dependientes de la aplicación sin cambios.
Además, hace posible añadir y eliminar productos en tiempo de ejecución
al invocar a la operación clonar, lo que supone un método que proporciona una
configuración dinámica de la aplicación.
Este patrón permite la especificación de nuevos objetos generando un
objeto con valores por defecto sobre el que posteriormente se podrán aplicarar
cambios. La especificación de nuevos objetos también puede realizarse mediante
la variación de su estructura. Reducción del número de subclases.
Desventajas
La jerarquía de prototipos debe ofrecer la posibilidad de clonar un
elemento y esta operación puede no ser sencilla de implementar. Por otro lado,
si la clonación se produce frecuentemente, el coste puede ser importante.
Otros detalles
Clonacion profunda vs Clonacion
superficial
Entre las diferentes modalidades entre las que puede optar a la hora de
implementar la clonación de un objeto prototipo, cabe destacar dos maneras de
realizar la clonación: superficial y profunda.
En la primera de ellas un cambio sobre el objeto asociado con un clon
afecta al objeto original, porque los objetos relacionados son los mismos (es
decir, la clonación replica sólo el propio objeto y su estado, no sus
asociaciones con terceros objetos), mientras que en la clonación profunda se
clonan los objetos y también sus objetos relacionados.
Soporte en Java
En Java disponemos de la interfaz cloneable y del Object Clone() throws
CloneNotSupportedException para llevar a cabo la implementación nuestro
prototipo de manera compatible con los prototipos ya existentes en las
librerías Java.
Negociador de Productos
Una modificación o derivación de este patrón es el conocido como
Negociador de Productos (Product Trader), que se centra en el tratamiento de
los prototipos cuando varios clientes trabajan sobre ellos. Este patrón
incorpora un gestor, normalmente utilizando el patron singleton, que actúa
sobre un conjunto de prototipos frente a los clientes.
Implementación
Lenguaje Java:
// Los productos deben implementar esta interface public interface Producto extends Cloneable { Object clone(); // Aquí van todas las operaciones comunes a los productos que genera la factoría } // Un ejemplo básico de producto public class UnProducto implements Producto { private int atributo; public UnProducto(int atributo) { this.atributo = atributo; } public Object clone() { return new UnProducto(this.atributo); } public String toString() { return ((Integer)atributo).toString(); } } // La clase encargada de generar objetos a partir de los prototipos public class FactoriaPrototipo { private HashMap mapaObjetos; private String nombrePorDefecto; public FactoriaPrototipo() { mapaObjetos = new HashMap(); // Se incluyen en el mapa todos los productos prototipo mapaObjetos.put("producto 1", new UnProducto(1)); } public Object create() { return create(nombrePorDefecto); } public Object create(String nombre) { nombrePorDefecto = nombre; Producto objeto = (Producto)mapaObjetos.get(nombre); return objeto != null ? objeto.clone() : null; } } public class PruebaFactoria { static public void main(String[] args) { FactoriaPrototipo factoria = new FactoriaPrototipo(); Producto producto = (Producto) factoria.create("producto 1"); System.out.println ("Este es el objeto creado: " + producto); } }
No hay comentarios:
Publicar un comentario