top of page

Prototype Design Pattern with Java

Updated: Apr 5, 2023

In software design, Prototype Design Pattern is a creational pattern that allows us to create objects from existing objects, thus reducing the need for creating new objects from scratch. This design pattern is used when we want to create new objects with the same properties as existing objects, but with different values. In this article, we will discuss the Prototype Design Pattern in detail and how it can be implemented in Java.


What is the Prototype Design Pattern?

The Prototype Design Pattern is a creational pattern that is used to create new objects from existing objects. The existing object acts as a prototype for the new object, and the new object is created by copying the properties of the existing object. This pattern is used when creating new objects from scratch is a time-consuming and resource-intensive process. Instead, the Prototype Design Pattern can be used to create new objects quickly and efficiently by copying the properties of existing objects.

Why do you need the Prototype Design Pattern?

Prototype Design Pattern is useful in scenarios where creating a new object is resource-intensive or complex. Instead of creating a new object from scratch, we can use an existing object as a prototype to create new objects with the same properties. This approach can be useful in situations where:

  1. The creation of an object is time-consuming or expensive, and we need to create multiple instances of the same object quickly and efficiently.

  2. Objects have a complex creation process, and creating new objects from scratch requires a lot of code duplication.

  3. We need to create multiple variants of an object that differ in only a few properties. In this case, we can create a prototype object with the common properties and then clone it to create new objects with varying properties.

Using the Prototype Design Pattern can help to reduce the amount of code needed to create new objects, improve performance, and promote code reuse. It can be particularly useful in situations where object creation is a bottleneck and needs to be optimized.

Implementation Steps

The first thing that strikes the mind when we hear a prototype is a “sample/template of any object before the actual object creation”.

So to understand what this prototype design pattern is, let’s assume a case study of a Bookshop.

We create a class Book.java with member variables as bid(Book Id) and bname(BookName) and for that, we need getters and setters for the same also we need to use the toString() method to print the object.

Book.java

package PrototypeDesign;  
public class Book {  
 private int bid;  
 private String Bname;  
 public int getBid() {  
 return bid;  
    }  
 public void setBid(int bid) {  
 this.bid = bid;  
    }  
 public String getBname() {  
 return Bname;  
    }  
 public void setBname(String bname) {  
        Bname = bname;  
    }  
 @Override 
 public String toString() {  
 return "Book [bid=" + bid + ", Bname=" + Bname + "]";  
    }  
} 

To open a BookShop, we need to create a class BookShop.java with member variables as shopName and the list of books i.e of type <Book> and for that, we need getters and setters with toString() method to print the object.

BookShop.java

package PrototypeDesign;  
import java.util.ArrayList;  
import java.util.List;  
public class BookShop //implementsCloneable 
{  
 private String shopname;  
    List < Book > book = new ArrayList < Book > ();  
 public String getShopname() {  
 return shopname;  
    }  
    publicvoidsetShopname(String shopname) {  
 this.shopname = shopname;  
    }  
 public List < Book > getBook() {  
 return book;  
    }  
    publicvoidsetBook(List < Book > book) {  
 this.book = book;  
    }  
 @Override 
 public String toString() {  
 return "BookShop [shopname=" + shopname + ", book=" + book + "]";  
    }  
}  

Let’s create an object of BookShop.java and now let's print this object.

BookShopTester.java

package PrototypeDesign;  
public class BookShopTester {  
 public static void main(String[] args) {  
        BookShop bs = new BookShop();  
        System.out.println(bs);  
    }  
}  

Output

BookShop [shopname=null, book=[]]

So we don’t want a BookShop which doesn’t have a name and a book list. We should assign some data, add a new method in BookShop.java.

public void loadData() {  
 for (int i = 1; i <= 5; i++) {  
        Book b = new Book();  
        b.setBid(i);  
        b.setBname("Book" + i);  
        getBook().add(b);  
    }  
}  

This method loadData() will add the data to the list and now we got BookShop with a new updated method and BookShopTester with the desired output.

BookShop.java(Updated)

package PrototypeDesign;  
import java.util.ArrayList;  
import java.util.List;  
public class BookShop //implementsCloneable 
{  
 private String shopname;  
    List < Book > book = new ArrayList < Book > ();  
 public String getShopname() {  
 return shopname;  
    }  
 public void setShopname(String shopname) {  
 this.shopname = shopname;  
    }  
 public List < Book > getBook() {  
 return book;  
    }  
 public void setBook(List < Book > book) {  
 this.book = book;  
    }  
 public void loadData() {  
 for (int i = 1; i <= 10; i++) {  
            Book b = new Book();  
            b.setBid(i);  
            b.setBname("Book" + i);  
            getBook().add(b);  
        }  
    }  
 @Override 
 public String toString() {  
 return "BookShop [shopname=" + shopname + ", book=" + book + "]";  
    }  
} 

BookShopTester.java(Updated)

package PrototypeDesign;  
public class BookShopTester {  
 public static void main(String[] args) {  
        BookShop bs = new BookShop();  
        bs.setShopname("R Lall Book Depot");  
        bs.loadData();  
        System.out.println(bs);  
    }  
}  


Output

BookShop [shopname=R Lal Book Depot, book=[Book [bid=1, Bname=Book1], Book [bid=2, Bname=Book2], Book [bid=3, Bname=Book3], Book [bid=4, Bname=Book4], Book [bid=5, Bname=Book5]]] 

What if we want a new object of BookShop in BookShopTester, we have to create a new object and load the data as done with the object(bs), and then it will take some time to load the data.

So we have the concept of cloning in Java that will copy the object from the old object.

To achieve cloning we have to give permission to BookShop.java class to implement an interface Cloneable. Thus, we need to @override the clone method in BookShop.java.


After updating all the methods and interfaces we have updated BookShop and BookShopTester classes below.

BookShop.java(Updated)

package PrototypeDesign;  
import java.util.ArrayList;  
import java.util.List;  
public class BookShop //implementsCloneable 
{  
 private String shopname;  
    List < Book > book = new ArrayList < Book > ();  
 public String getShopname() {  
 return shopname;  
    }  
 public void set Shopname(String shopname) {  
 this.shopname = shopname;  
    }  
 public List < Book > getBook() {  
 return book;  
    }  
 public void setBook(List < Book > book) {  
 this.book = book;  
    }  
 public void loadData() {  
 for (int i = 1; i <= 10; i++) {  
            Book b = new Book();  
            b.setBid(i);  
            b.setBname("Book" + i);  
            getBook().add(b);  
        }  
    }  
 @Override 
 public String toString() {  
 return "BookShop [shopname=" + shopname + ", book=" + book + "]";  
    }  
 @Override 
 protected BookShop clone() throws CloneNotSupportedException {  
 //code to achieve deep cloning instead of shallow cloning 
        BookShop shop = new BookShop();  
 for (Book b: this.getBook()) {  
            shop.getBook().add(b);  
        }  
 return shop;  
    }  
} 

BookShopTester.java(Updated)

package PrototypeDesign;  
public class BookShopTester {  
 public static void main(String[] args) throws CloneNotSupportedException {  
        BookShop bs = new BookShop();  
        bs.setShopname("R Lall Book Depot");  
        bs.loadData();  
        BookShop bs1 = bs.clone();  
        bs.getBook().remove(2); //to achieve deep cloning 
        bs1.setShopname("Khurana Books");  
        System.out.println(bs);  
        System.out.println();  
        System.out.println(bs1);  
    }  
} 

Output:

BookShop [shopname=R Lal Book Depot, book=[Book [bid=1, Bname=Book1], Book [bid=2, Bname=Book2], Book [bid=4, Bname=Book4], Book [bid=5, Bname=Book5]]]
BookShop [shopname=Khurana Books, book=[Book [bid=1, Bname=Book1], Book [bid=2, Bname=Book2], Book [bid=3, Bname=Book3], Book [bid=4, Bname=Book4], Book [bid=5, Bname=Book5]]]

Note

That’s the power of the prototype method, for any new method we don’t need to load data again from the database as it will lead to more time complexity i.e for the first object we are loading data from the database but for the second object, we are just cloning the object.

Here, in the above code bs.getBook().remove(2); will help in checking whether we have one object two references or if we have a copy of the first object; i.e after removing data from the first object the data for the second object remains unchanged and that is deep cloning.

Advantages of Prototype Design Pattern

Here are the advantages of the Prototype Design Pattern in Java:

  • Reduces the need for creating new objects from scratch

  • Helps to improve performance by creating new objects quickly and efficiently

  • Promotes code reuse by reducing the amount of code needed to create new objects

  • Simplifies the creation of complex objects by using an existing object as a prototype

  • Allows for the creation of multiple variants of an object with different properties by cloning a prototype object

  • Provides a flexible way to create new objects by modifying the properties of an existing object

  • Helps to reduce the amount of code duplication needed to create new objects


Usage of Prototype Design Pattern

Here are some usage scenarios of the Prototype Design Pattern in Java:

  • Creating objects that are expensive to create from scratch

  • Creating objects that require a lot of time and effort to initialize

  • Creating objects with complex initialization processes

  • Creating objects with a high degree of similarity to existing objects

  • Creating multiple variants of an object with different properties

  • Creating objects with a dynamic type at runtime


Conclusion

Prototype Design Patterns can help to improve performance, promote code reuse, simplify object creation, and reduce code duplication. The Prototype Design Pattern is particularly useful in situations where object creation is resource-intensive or complex and where multiple instances of the same object need to be created quickly and efficiently. By using the Prototype Design Pattern, developers can create high-quality, scalable, and maintainable code that is easier to modify and extend over time.

0 comments
bottom of page