Patrón de diseño Prototype en Java

Prototype Pattern

Prototype Pattern


Siguiendo con los patrones de diseño en Java, vamos a ver como podemos construir y hacer uso del Patrón de diseño Prototype, el cual se encuentra dentro de los patrones de diseño creacionales.

La idea del patrón Prototype, el cual pertenece a la clasificación de patrones creacionales, es permitir copiar un objeto existente sin que tu código dependa de esas clases.

Cuándo usar el Patrón Prototype

Vamos a hacer uso del patrón Prototype cuando queramos realizar un clonado de un objeto. Pero ante esta tesitura nos pueden surgir algún problema, qué hacemos con aquellos campos que son privados, o que tengan interfaces, parámetros etc…,

Para realizar un clonado y evitar los problemas añadidos de como realizar su clonación cuando no todo es un caso sencillo con campos públicos hacemos uso del Patrón Prototype.

El Patrón Prototype, también puede ser usado cuando tenemos herencia entre nuestros objetos y estos difieren en pocos o en ningún campo, para esos casos en los que necesitemos realizar copias de los objetos padre podemos utilizar este patrón y reducir el boilerplate de nuestro código.

Cómo aplicar el Patrón Prototype

La idea del patrón Prototype es delegar el proceso de clonado de cualquier objeto al objeto que queremos clonar.

El patrón Prototype nos declara una interfaz que va a ser común para ser utilizada por todos aquellos objetos que queramos clonar, esto nos permite un gran desacople de nuestros objetos y clases.

La implementación que vamos a realizar creará un objeto de la clase que queremos crear y además todas sus relaciones y objetos asociados.

El uso de Clone es ampliamente conocido y utilizado en Java, pero pocas veces se sabe que se encuentra creado haciendo uso del patrón prototype.

Implementación Patrón Prototype

A continuación mostramos la implementación del Patrón Builder.

Patrón Builder | Patrón de diseño Prototype en Java
Patrón Builder

El objetivo del Patrón Builder, como hemos comentado antes, es crear un clone de un objeto ya existente.

Los pasos que se tienen que llevar a cabo para realizar esta implementación son:

  • La interfaz que hemos creado tiene que declarar el método clone() para poder realizar la copia exacta del objeto.
  • La clase (Prototype Class) que extiende de la interfaz será la encargada de implementar el método de clonar (clone()).

Ejemplo de Patrón Prototype

Siguiendo el diagrama que hemos realizado en el punto anterior, vamos a realizar un ejemplo con su implementación del Patrón Prototype.

En nuestro caso tenemos una clase abstracta «padre» que será Animal y un Cat y un Parrot que extienden de esa interfaz y haremos una copia (clone) de Cat y Parrot.

Si quieres puedes ver el ejemplo en Java directamente en nuestro github.

Creación de la clase principal

El primer paso es crear una clase abstracta en donde tenemos el método clone(). Además en nuestro caso de ejemplo redefinimos el método equals y añadimos algunos campos más.

package com.refactorizando.patterns.prototype;

import java.util.Objects;

public abstract class Animal {
  public int legs;
  public boolean omnivorous;
  public boolean mammal;
  public String color;

  public Animal() {
  }

  public Animal(Animal target) {
    if (target != null) {
      this.legs = target.legs;
      this.omnivorous = target.omnivorous;
      this.mammal = target.mammal;
      this.color = target.color;

    }
  }

  public abstract Animal clone();

  @Override
  public boolean equals(Object object2) {
    if (!(object2 instanceof Animal)) return false;
    Animal animal2 = (Animal) object2;
    return animal2.omnivorous = omnivorous && animal2.legs == legs
        && animal2.mammal == mammal && Objects.equals(animal2.color, color);
  }
}

Implementación de clase hija y método Clone()

Una vez hemos definido la clase principal, es momento a crear las clases hijas que van a heredar de la clase padre y a redefinir los métodos. Además se realizará la definición del método clone(), el cual nos permite implementar el patron Prototype.

La siguiente clase se encargará de extender de la clase padre Animal y de implementar el método clone(), el cual creará un nuevo objeto completo de la clase.

package com.refactorizando.patterns.prototype;

public class Cat extends Animal{

  public Boolean flexibility;

  public Cat() {
  }

  public Cat(Cat cat) {
    super(cat);
    if (cat != null) {
      this.flexibility = cat.flexibility;
    }
  }

  @Override
  public Animal clone() {
    return new Cat(this);
  }

  @Override
  public boolean equals(Object object2) {
    if (!(object2 instanceof Cat) || !super.equals(object2)) return false;
    Cat Animal2 = (Cat) object2;
    return Animal2.flexibility == flexibility;
  }
}

Desarrollo de clase hija en el Patrón Prototype

A continuación al igual que hemos hecho con la clase Cat, vamos a implementar la Clase Parrot, que únicamente tendrá un nuevo campo. Esta clase tendrá la misma lógica que Cat, el punto importante es la definición del método clone().

package com.refactorizando.patterns.prototype;

public class Parrot extends Animal{

  public String phrase;

  public Parrot() {
  }

  public Parrot(Parrot parrot) {
    super(parrot);
    if (parrot!= null) {
      this.phrase = parrot.phrase;
    }
  }

  @Override
  public Animal clone() {
    return new Parrot(this);
  }

  @Override
  public boolean equals(Object object2) {
    if (!(object2 instanceof Parrot) || !super.equals(object2)) return false;
    Parrot shape2 = (Parrot) object2;
    return shape2.phrase == phrase;
  }

}

Ejecución para probar el Patron Builder

Una vez hemos realizado las implementaciones de las clases respectivas vamos a crear una ejecución para poder verificar que los objetos Parrot y Cat se clonan correctamente:

package com.refactorizando.patterns.prototype;

import java.util.ArrayList;
import java.util.List;

public class Application {

  public static void main(String[] args) {
    List<Animal> animals = new ArrayList<>();

    Cat cat = new Cat();
    cat.legs = 4;
    cat.mammal = true;
    cat.omnivorous = true;
    cat.color = "black";
    cat.flexibility = true;
    animals.add(cat);

    Cat anotherCat = (Cat) cat.clone();
    animals.add(anotherCat);

    Parrot parrot = new Parrot();
    parrot.phrase = "Hello, how are you?";
    parrot.color = "yellow";
    parrot.legs = 2;
    parrot.mammal = false;
    parrot.omnivorous = true;
    animals.add(parrot);

    Parrot anotherParrot = (Parrot) parrot.clone();
    animals.add(anotherParrot);


    System.out.println("Cats equals " + animals.get(0).equals(animals.get(1)));
    System.out.println("Parrots equals " +animals.get(2).equals(animals.get(3)));
  }

}

Pros de Patrón Prototype

Podemos crear copias de objetos sin tener que realizar muchas implementaciones en el código y permitir aislar las clases.

Podemos realizar copias de objetos completos sin tener que añadir más clases o métodos a nuestros objetos.

Contras de Patrón Prototype

Referencias circulares entre objetos puede hacer complejo realizar el clonado de un objeto.

Conclusión

En esta entrada hemos visto el Patrón de Diseño Prototype con un ejemplo de implementación en Java. El Patrón de diseño Prototype nos ayudará a tener un código más legible, flexible y extensible en el desarrollo de nuestras aplicaciones.

Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com o también nos puedes contactar por nuestras redes sociales Facebook o twitter y te ayudaremos encantados!


Deja una respuesta

Tu dirección de correo electrónico no será publicada.