Patrones de diseño de creación: Prototype

Intención del patrón
  • Especifica los tipos de objetos a crear utilizando una instancia prototipo, y crear nuevos objetos mediante la copia de este prototipo.
  • Cooptación de una instancia de una instancia para usarlo como un prototipo de todas las instancias futuras.

Ejemplo de problema
La aplicación especifica de forma dura la clase de objeto que debe crear con cada expresión new.


Discusión
Declarar una clase abstracta que especifica un método virtual puro "Clone", y mantener un diccionario con todos las clases derivadas concretas "Clonable". Cualquier clase que necesite un "constructor polimórfico", deriva de la clase base abstracta, registra su instancia prototípica e implementa su método Clone().
El cliente entonces, en lugar de escribir código que invoque al operador new en una clase hardcodeada, llama al método Clone en la clase base abstracta, proveyendo una cadena o un tipo de dato enumerado (enum) que designa la clase derivada concreta en particular que se desea.

Estructura
La Factoría conoce cómo encontrar el Prototipo correcto y cada Producto conoce la forma de generar nuevas instancias de sí mismo.

Ejemplo
El patrón Prototype especifica el tipo de objetos a crear usando una instancia prototípica. Los prototipos de nuevos productos son a menudo se construyen antes de la producción total, pero en este ejemplo, el prototipo es pasivo y no participa en la copia de sí mismo. La división por mitosis de una célula (resultando en dos células idénticas) es un ejemplo de prototipo que juega un rol activo en la copia de sí mismo y por lo tanto, demuestra el patrón Prototype. Cuando una célula se divide, resultan dos células de genotipo idéntico. En otras palabras, se clona a sí misma.

Check list

  1. Agregar un método Clone() a la jerarquía de "producto" actual.
  2. Diseñar un "registro" que mantenga un caché de objetos prototipo. el Registro debe ser encapsulado en una nueva clase Factory o en la clase base de la jerarquía de producto.
  3. Diseñar un Factory Method que: pueda (o no) aceptar argumentos, encuentre el prototipo de objeto correcto, llame al método Clone() de dicho prototipo y retorne el resultado.
  4. Reemplazar en el cliente todas las referencias al operador new y por la llamada al Factory Method.


Reglas de oro

  • Algunas veces, los patrones creacionales son competidores: existen casos en los cuales no se puede usar ni un Prototype ni un Abstract Factory. En otras ocasiones pueden ser complementarios: Abstract Factory puede almacenar un conjunto de Prototypes de los cuales clonar y retornar el objeto deseado. Abstract Factory, Builder y Prototype pueden usar Singleton en su implementación.
  • Las clases de Abstract Factory son a menudo implementadas con Factory Methods, pero ellos pueden ser implementados usando Prototype.
  • Factory Method: Creación a través de herencia. Prototype: Creación a través de la delegación.
  • A menudo, el diseño se comienza usando Factory Method (Menos complicado, más personalizable, prosperan las subclases) para luego evolucionar hacia Abstract FactoryPrototype Builder (Más flexible, más complejo) a medida que el diseñador descubre dónde se necesita más flexibilidad.
  • Prototype no requiere subclaseado, pero si requiere un método de inicialización. Factory Method requiere subclaseo pero no requiere inicialización.
  • Los diseños que hacen uso intensivo de los patrones Composite y Decorator se pueden ver beneficiados con Prototype.
  • Prototype coopta una instancia de una clase para usarla como semilla de futuras instancias.
  • Los prototipos resultan útiles cuando la inicialización es costosa, y se prevé poca variación en los parámetros de inicialización. En este contexto, Prototype puede evitar costosas "creaciones desde cero" y soportar una barata clonación de un prototipo pre inicializado.
  • Prototype es único entre los otros patrones de diseño creacionales ya que no requiere una clase, sólo un objeto. Lenguajes orientados a objeto tales como Self u Omega, que hacen a un lado las clases, dependen completamente de los prototipos para la creación de nuevos objetos.


Ejemplo de código en C#
using System;

namespace DoFactory.GangOfFour.Prototype.Structural 
{
 
  // MainApp test application
  class MainApp
  {
 
    static void Main()
    {
      // Create two instances and clone each 
      ConcretePrototype1 p1 = new ConcretePrototype1("I");
      ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
      Console.WriteLine ("Cloned: {0}", c1.Id);

      ConcretePrototype2 p2 = new ConcretePrototype2("II");
      ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
      Console.WriteLine ("Cloned: {0}", c2.Id);

      // Wait for user 
      Console.Read();
    }
  }

  // "Prototype" 
  abstract class Prototype
  {
    private string id;

    // Constructor 
    public Prototype(string id)
    {
      this.id = id;
    }

    // Property 
    public string Id
    {
      get{ return id; }
    }

    public abstract Prototype Clone();
  }

  // "ConcretePrototype1" 
  class ConcretePrototype1 : Prototype
  {
    // Constructor 
    public ConcretePrototype1(string id) : base(id) 
    {
    }

    public override Prototype Clone()
    {
      // Shallow copy 
      return (Prototype)this.MemberwiseClone();
    }
  }

  // "ConcretePrototype2" 
  class ConcretePrototype2 : Prototype
  {
    // Constructor 
    public ConcretePrototype2(string id) : base(id) 
    {
    }

    public override Prototype Clone()
    {
      // Shallow copy 
      return (Prototype)this.MemberwiseClone();
    }
  }
}

2 comentarios:

Anónimo dijo...

En el ejemplo no se ve claro qué sucede con el "id" que se le pasa al constructor del Prototipo y no hay referencia al registro caché de objetos prototipo

Juan Barrionuevo dijo...

Hola Anónimo, muchas gracias por dejarnos tu comentario.

El "Id" que se le pasa en el constructor al proptotipo concreto, es enviado a la clase base abstracta y ésta lo asigna a la propiedad homónima.
Por otra parte, en el ejemplo no se hace referencia a un caché dado que no hay una factoría propiamente dicha sino que para resumir el ejemplo, el trabajo de la misma puede verse en el método main() en el cual puede verse que se construye un objeto del tipo concreto Protoype1 y luego éste puede ser clonado. Lo mismo pasa con el tipo concreto Prototype2.

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere