Patrón Prototipo

El patrón prototipo (Prototype Pattern) se utiliza para crear objetos duplicados garantizando al mismo tiempo el rendimiento. Este tipo de patrón de diseño pertenece a los patrones creacionales y proporciona una de las mejores formas de crear objetos.

Este patrón implementa una interfaz de prototipo, que se utiliza para crear clones del objeto actual. Cuando el coste de crear directamente un objeto es relativamente alto, se adopta este patrón. Por ejemplo, si un objeto necesita ser creado después de una operación de base de datos costosa, podemos almacenar en caché ese objeto, devolver su clon en la siguiente solicitud y actualizar la base de datos cuando sea necesario, reduciendo así las llamadas a la base de datos.

Resumen

Patrón Prototipo

Intención: Utilizar instancias de prototipo para especificar los tipos de objetos a crear, y crear nuevos objetos copiando estos prototipos.

Solución principal: Crear y eliminar prototipos dinámicamente en tiempo de ejecución.

Cuándo usarlo

  • El sistema debe ser independiente de la creación, composición y representación de los productos.
  • Es necesario especificar la clase a instanciar en tiempo de ejecución, por ejemplo, mediante carga dinámica.
  • Evitar crear una jerarquía de clases de fábrica paralela a la jerarquía de clases de producto.
  • Cuando las instancias de una clase solo pueden tener unas pocas combinaciones de estados diferentes, clonar el prototipo es más conveniente que la instanciación manual.

Cómo resolverlo

Generar rápidamente instancias idénticas al objeto prototipo utilizando un objeto prototipo existente.

Código clave

  • Implementar la operación de clonación:
    • En Java, implementar la interfazCloneabley sobrescribir el métodoclone().
    • En .NET, usar la claseObjecty el métodoMemberwiseClone()para implementar una copia superficial, o mediante serialización para implementar una copia profunda.
  • Aislar el acoplamiento entre los usuarios de los objetos de clase y los tipos concretos, exigiendo que las "clases cambiantes" tengan una interfaz estable.

Ejemplos de aplicación

  • División celular
  • El métodoObject.clone()en Java.

Ventajas

  • Mejora del rendimiento
  • Evita las restricciones del constructor

Desventajas

  • Dotar de un método de clonación requiere considerar exhaustivamente la funcionalidad de la clase, y puede resultar difícil de implementar para clases existentes, especialmente al tratar con objetos indirectos que no admiten serialización o con referencias que contienen estructuras cíclicas.
  • Debe implementar la interfazCloneable.

Escenarios de uso

  • Optimización de recursos
  • La inicialización de la clase requiere consumir una gran cantidad de recursos (como datos o recursos de hardware).
  • Escenarios con altos requisitos de rendimiento y seguridad
  • Cuando la creación de objetos mediantenewrequiere una preparación de datos compleja o permisos de acceso.
  • Cuando un objeto necesita múltiples modificadores.
  • Cuando un objeto debe ser accesible para otros objetos y puede ser modificado por distintos llamadores.
  • Normalmente se utiliza junto con el patrón de método de fábrica; medianteclonese crean objetos, que luego el método de fábrica proporciona al llamador.

Notas

A diferencia de crear nuevos objetos mediante la instanciación directa de clases, el patrón prototipo genera nuevos objetos copiando objetos existentes. La copia superficial se implementa medianteCloneabley la copia profunda medianteSerializableque lee el flujo binario.

Estructura

El patrón prototipo incluye los siguientes roles principales:

  • Interfaz de prototipo (Prototype Interface): Define una interfaz para clonarse a sí mismo, que generalmente incluye un métodoclone().

  • Clase prototipo concreta (Concrete Prototype): Es la clase concreta que implementa la interfaz de prototipo y se encarga de la operación real de clonación. Esta clase debe implementar el métodoclone(), generalmente utilizando copia superficial o copia profunda para duplicarse a sí misma.

  • Cliente (Client): Utiliza instancias de prototipo para crear nuevos objetos. El cliente llama al métodoclone()del objeto prototipo para crear nuevos objetos, en lugar de utilizar directamente el constructor.

Implementación

Vamos a crear una clase abstractaShapey las clases de entidad que extiendenShapela clase. El siguiente paso es definir la claseShapeCache, que almacena los objetos shape en unHashtabley devuelve sus clones cuando se solicita.

PrototypePatternDemoLa claseShapeCacheutiliza la clase para obtener los objetosShape.

原型模式的 UML 图

Paso 1

Crear una clase abstracta que implemente la interfazCloneable.

Shape.java

public abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType(){ return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }

Paso 2

Crear las clases de entidad que extienden la clase abstracta anterior.

Rectangle.java

public class Rectangle extends Shape { public Rectangle(){ type = "Rectangle"; } @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }

Square.java

public class Square extends Shape { public Square(){ type = "Square"; } @Override public void draw() { System.out.println("Inside Square::draw() method."); } }

Circle.java

public class Circle extends Shape { public Circle(){ type = "Circle"; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }

Paso 3

Crear una clase que obtenga las clases de entidad de la base de datos y las almacene en unHashtable.

ShapeCache.java

import java.util.Hashtable; public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); } //Ejecutar una consulta de base de datos para cada forma y crear la forma // shapeMap.put(shapeKey, shape); //Por ejemplo, vamos a añadir tres formas: public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(),circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(),square); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(),rectangle); } }

Paso 4

PrototypePatternDemoUtilizar la claseShapeCachepara obtener los clones de las formas almacenados enHashtable.

PrototypePatternDemo.java

public class PrototypePatternDemo { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = (Shape) ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape.getType()); Shape clonedShape2 = (Shape) ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); Shape clonedShape3 = (Shape) ShapeCache.getShape("3"); System.out.println("Shape : " + clonedShape3.getType()); } }

Paso 5

Ejecutar el programa y mostrar el resultado:

Shape : Circle
Shape : Square
Shape : Rectangle
Otras extensiones