Skip to content

Prototype

Construction

The prototype is a design pattern that allows you to create objects in two stages:

  • creating a base object (e.g. partially completed) which is a copy of the ready object
  • setting the rest of the object's fields.

This pattern can be used when we are working on a large application where performance is a key factor. Creating a prototype can improve the performance of our application.

Shallow and Deep Copy

Copying the base part can be done in many ways. We can use the Cloneable interface and the clone method or implement the copying mechanism ourselves. It may be a good idea to use a finished, tested solution from an external library.

We must take into account whether we want to perform the so-called shallow copy (i.e. copy all fields with ==) or the so-called deep copy, which will create a new copy of the object referenced by each reference in the object.

Example

The following example shows a simple prototype implementation that uses the clone method and theCloneable interface. The cloned object has actually copied the fields (i.e. we get an actual copy of the object even though the clone method doesshallow copy), but this is due to the types that the JavaCodeFile class uses (String is a special object in Java).

public class JavaCodeFile implements Cloneable {
  private String licenseContent;
  private String code;
  private String fileName;
  private String fileExtension;

  public JavaCodeFile(final String licenseContent, final String fileExtension) {
    this.licenseContent = licenseContent;
    this.fileExtension = fileExtension;
  }

  public JavaCodeFile(final String licenseContent, final String code, final String fileName, final String fileExtension) {
    this.licenseContent = licenseContent;
    this.code = code;
    this.fileName = fileName;
    this.fileExtension = fileExtension;
  }

  public String getLicenseContent() {
    return licenseContent;
  }

  public void setLicenseContent(final String licenseContent) {
    this.licenseContent = licenseContent;
  }

  public String getCode() {
    return code;
  }

  public void setCode(final String code) {
    this.code = code;
  }

  public String getFileName() {
    return fileName;
  }

  public void setFileName(final String fileName) {
    this.fileName = fileName;
  }

  public String getFileExtension() {
    return fileExtension;
  }

  public void setFileExtension(final String fileExtension) {
    this.fileExtension = fileExtension;
  }

  public JavaCodeFile createClone() throws CloneNotSupportedException {
    return (JavaCodeFile)clone();
  }

  @Override
  public String toString() {
    return "JavaCodeFile{" +
        "licenseContent='" + licenseContent + '\'' +
        ", code='" + code + '\'' +
        ", fileName='" + fileName + '\'' +
        ", fileExtension='" + fileExtension + '\'' +
        '}';
  }
}
public class JavaCodeFilesManager {

  private static final JavaCodeFile BASE_FILE = new JavaCodeFile("SDA License", "java");

  public JavaCodeFile createFileWithContent(final String fileName, final String content) throws CloneNotSupportedException {
    JavaCodeFile baseFileClone = BASE_FILE.createClone(); // Use of the prototype
    baseFileClone.setCode(content); // setting the rest of the object's fields
    baseFileClone.setFileName(fileName);
    return baseFileClone;
  }
}

Using the pattern:

public class SimplePrototypeDemo {
  public static void main(String[] args) throws CloneNotSupportedException {
    final JavaCodeFilesManager javaCodeFilesManager = new JavaCodeFilesManager();
    JavaCodeFile fileA = javaCodeFilesManager.createFileWithContent("Integers", "int x = 3;");
    JavaCodeFile fileB = javaCodeFilesManager.createFileWithContent("Strings", "String y = \"3\";");

    System.out.println(fileA);
    System.out.println(fileB);
  }
}