Cidenet+Blog+Desarrollo limpio+Prototype

Prototype

¿Qué es?, ¿Qué problema resuelve?

Prototype permite esconder la creación de nuevos objetos desde el cliente. Consiste en copiar un objeto existente en lugar de crear uno nuevo desde cero, algo que puede incluir operaciones costosas. El objeto existente actúa como un prototipo y contiene el estado del objeto. El objeto nuevo puede cambiar sus propiedades solo si es requerido. Este acercamiento ahorra recursos y tiempo, especialmente cuando la creación del objeto es un proceso pesado.

Diagrama

  • Prototype: Declara una interfaz para clonarse a sí mismo.
  • ConcretePrototype: Implementa una operación para clonarse a sí mismo.
  • Client: Crea un objeto nuevo haciendo una petición a un Prototype de que se clone a sí mismo.

Ejemplo

En general, todo objeto que tenga un proceso de creación pesado y que necesite crearse varias veces, es indicio de que se puede utilizar Prototype. Este patrón también puede ser usado en objetos que comparten la misma estructura, tienen valores idénticos, pero difieren en algún valor.
En este ejemplo utilizamos la interfaz Cloneable, la clase que implementa esta interfaz indica al método Object.clone() que es legal hacer una copia campo a campo de instancias de esa clase. Si se utiliza el método clone sin implementar esta interfaz se lanza CloneNotSupportedException.

En este ejemplo lo implementaremos para crear una notificación de correo con un mismo asunto y un mismo mensaje para diferentes correos. Nótese que en el constructor (Imagen 2) se hacen unas preparaciones a ciertos parámetros antes de ser asignados, con Prototype ganamos hacer esta lógica solo una vez y no por cada Notificación nueva que se cree.

public Notification(String email, String message, String subject, String sender, String attachedRoute) {
   this.email = email;
   this.message = message;
 this.subject = subject.replaceAll("á", "aacute;").replaceAll("é", "eacute").trim().substring(3);
   this.sender = sender;
   this.attachedRoute = attachedRoute.replaceAll("/+", "/").trim();
}

En la imagen 3 se muestra cómo por cada notificación que se debe crear se instancia un objeto de la clase Notification, teniendo que hacer por cada una de estos las validaciones existentes en el constructor. Hay que tener en cuenta que estas validaciones pueden llegar a ser muy pesadas.

public static List<Notification> createNotifications(List<String> emails) {
   String message = "Same message for everyone";
   String subject = "Subject";
   String sender = "Same sender";
   String attachedRoute = "Same route";
   return emails
          .stream()
       .map(email -> new Notification(email, message, subject, sender, attachedRoute))
           .collect(Collectors.toList());
}

Estas validaciones repetidas se pueden evitar haciendo uso de prototipos. Para esto, en esta clase también se implementa el método clone, el cual llama al constructor padre para que se realice la copia campo a campo de un objeto a otro.

@Override
public Notification clone() throws CloneNotSupportedException {
   return ((Notification) super.clone());
}

Teniendo esto, ya símplemente se debe crear una notificación nueva y a partir de este prototipo, se crean n notificaciones que sólo van a ser diferentes en su correo. Por medio del método clone se están copiando los campos del prototipo inicial a cada nueva notificación, evitando así hacer validaciones que se hacen en el constructor.

public static List<Notification> createNotifications(List<String> emails) {
   Notification notification = new Notification("", "Message", "Subject", "Sender", "route");
   return emails
           .stream()
           .map(email -> {
               try {
                   Notification notification1 = notification.clone();
                   notification1.setEmail(email);
                   return notification1;
               } catch (CloneNotSupportedException e) {
                  e.printStackTrace();
               	return new Notification("", "Message", "Subject", "Sender", "route");
               }
           })
           .collect(Collectors.toList());
}

El ejemplo completo se encuentra en https://bit.ly/3i4xtFC

Conclusiones

  • En general, si se debe crear cierta cantidad de instancias de una clase y entre estas instancias hay valores en común, es un signo de que se puede utilizar Prototype.
  • Usar el patrón cuando se quiera reducir el número de subclases que solo difieren en la forma que estas inicializas sus respectivos objetos.
  • El patrón Prototype permite usar un conjunto de objetos preconstruidos, configurados de diferentes formas, como prototipos.
  • En lugar de instanciar una subclase que se ajusta a cierta configuración, el código cliente simplemente busca por un prototipo apropiado a fin de clonarlo.
  • Es un patrón muy útil para la creación de interfaces, ya que se puede tener un prototipo de un elemento gráfico, clonarlo y solo cambiar las propiedades o estilos necesarios.

Fuentes

Contáctanos

Déjanos tus datos

    Medellín - Colombia

  • Calle 47D #72-29
  • (+57) 4 3222567
  • comunicaciones@cidenet.com.co

    Estados Unidos

  • 1200 Colorado Blvd, Denver Colorado 80220
  • (+1) 7723619239
  • jceballos@cidenet.net
WhatsApp
>