Cidenet+Blog+Clean Dev Practices+Prototype

Prototype

What is it? What issue does it solve?

Prototype allows us to hide the creation of new objects from the client. It consists of copying an existing object rather than creating a new one from scratch, which can imply costly operations. The existing object acts as a prototype and contains the state of the object. The new object can change its properties only if it is required to do so. This approach saves expensive resources and time, especially when object creation is a heavy process.

Diagram

  • Prototype: Declares an interface to clone itself.
  • ConcretePrototype: Implements an operation to clone itself.
  • Client: Creates a new object by requesting a Prototype to clone itself.Ejemplo

Example

In general, any object that has a heavy creation process and needs to be created multiple times gives us an indication that Prototype can be implemented. This pattern can also be used on objects that share the same structure or have identical values, but differ in a value.

In this example, we use the Cloneable interface, the class that implements this interface tells the Object.clone() method that it is legal to make a field-by-field copy of instances of that class. If the clone method is used without implementing this interface, CloneNotSupportedException is thrown.

In this example, we will implement it to create an email notification with the same subject and the same message for different emails. Note that in the constructor (Image 2) some preparation of certain parameters is done before being assigned. With Prototype, we manage to do this logic only once and not for each new Notification that is created.

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();
}

Image 3 shows how for each notification that must be created, an object of the Notification class is instantiated, having to do the existing validations in the constructor for each of these. Keep in mind that such validations may get a little heavy.

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());
}

These repeated validations can be avoided by making use of prototypes. 

This class also implements the clone method, which calls the parent constructor to make the copy, field by field, from one object to another.

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

This being provided, you only have to create a new notification and, from this prototype, notifications are created that will only be different in their mail field. Through the clone method, the fields of the initial prototype are being copied to each new notification, thus avoiding the validations that are made in the 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());
}

Example can be found at: https://bit.ly/3i4xtFC

Conclusions

  • In general, if a certain number of instances of the same class must be created and there are values in common between these instances, it is a sign that the  Prototype pattern can be used.
  • Use this pattern when you want to reduce the number of subclasses that only differ in the way they initialize their respective objects.
  • The Prototype pattern allows you to use a set of pre-built objects, configured in different ways, as prototypes.
  • Instead of instantiating a subclass that conforms to a certain configuration, the client code just searches for an appropriate prototype to clone it.
  • It is a very useful pattern for creating interfaces since you can have a prototype of a graphic element, clone it, and only change the necessary properties or styles.

Sources

Contact us

Allow us to contact you

    Medellín - Colombia

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

    United States

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