Core Java

Prototype Design Pattern Example

This article is part of our Academy Course titled Java Design Patterns.

In this course you will delve into a vast number of Design Patterns and see how those are implemented and utilized in Java. You will understand the reasons why patterns are so important and learn when and how to apply each one of them. Check it out here!

1. Introduction

In Object Oriented Programming, you need objects to work with; objects interact with each other to get the job done. But sometimes, creating a heavy object could become costly, and if your application needs too many of that kind of objects (containing almost similar properties), it might create some performance issues.

Let us consider a scenario where an application requires some access control. The features of the applications can be used by the users according to the access rights provided to them. For example, some users have access to the reports generated by the application, while some don’t. Some of them even can modify the reports, while some can only read it. Some users also have administrative rights to add or even remove other users.

Every user object has an access control object, which is used to provide or restrict the controls of the application. This access control object is a bulky, heavy object and its creation is very costly since it requires data to be fetched from some external resources, like databases or some property files etc.

We also cannot share the same access control object with users of the same level, because the rights can be changed at runtime by the administrator and a different user with the same level could have a different access control. One user object should have one access control object.

We can use the Prototype Design Pattern to resolve this problem by creating the access control objects on all levels at once, and then provide a copy of the object to the user whenever required. In this case, data fetching from the external resources happens only once. Next time, the access control object is created by copying the existing one. The access control object is not created from scratch every time the request is sent; this approach will certainly reduce object creation time.

Before digging into the solution, let us know more about the Prototype Design Pattern.

2. What is the Prototype Design Pattern

The Prototype design pattern is used to specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

The concept is to copy an existing object rather than creating a new instance from scratch, something that may include costly operations. The existing object acts as a prototype and contains the state of the object. The newly copied object may change same properties only if required. This approach saves costly resources and time, especially when the object creation is a heavy process.

In Java, there are certain ways to copy an object in order to create a new one. One way to achieve this is using the Cloneable interface. Java provides the clone method, which an object inherits from the Object class. You need to implement the Cloneable interface and override this clonemethod according to your needs.

class_diagram_1
Figure 1

Prototype

  • Declares an interface for cloning itself.

ConcretePrototype

  • Implements an operation for cloning itself.

Client

  • Creates a new object by asking a prototype to clone itself.

Prototypes let you incorporate a new concrete product class into a system simply by registering a prototypical instance with the client.

3. Solution to the Problem

In this solution, we will use the clone method to solve the above problem.

package com.javacodegeeks.patterns.prototypepattern;

public interface Prototype extends Cloneable {

	public AccessControl clone() throws CloneNotSupportedException;

}

The above interface extends the Cloneable interface and contains a method clone. This interface is implemented by classes which want to create a prototype object.

package com.javacodegeeks.patterns.prototypepattern;

public class AccessControl implements Prototype{

	private final String controlLevel;
	private String access;

	public AccessControl(String controlLevel,String access){
		this.controlLevel = controlLevel;
		this.access = access;
	}

	@Override
	public AccessControl clone(){
		try {
			return (AccessControl) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String getControlLevel(){
		return controlLevel;
	}

	public String getAccess() {
		return access;
	}

	public void setAccess(String access) {
		this.access = access;
	}

}

The AccessControl class implements the Prototype interface and overrides the clone method. The method calls the clone method of the super class and returns the object after down-casting it to the AccessControl type. The clone method throws CloneNotSupportedException which is caught within the method itself.

The class also contains two properties; the controlLevel is used to specific the level of control this object contains. The level depends upon the type of user going to use it, for example, USER, ADMIN, MANAGER etc.

The other property is the access; it contains the access right for the user. Please note that, for simplicity, we have used access as a String type attribute. This could be of type Map which can contain key value pairs of long access rights assigned to the user.

package com.javacodegeeks.patterns.prototypepattern;

public class User {

	private String userName;
	private String level;
	private AccessControl accessControl;

	public User(String userName,String level, AccessControl accessControl){
		this.userName = userName;
		this.level = level;
		this.accessControl = accessControl;
	}

	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getLevel() {
		return level;
	}
	public void setLevel(String level) {
		this.level = level;
	}
	public AccessControl getAccessControl() {
		return accessControl;
	}
	public void setAccessControl(AccessControl accessControl) {
		this.accessControl = accessControl;
	}

	@Override
	public String toString(){
		return "Name: "+userName+", Level: "+level+", Access Control Level:"+accessControl.getControlLevel()+", Access: "+accessControl.getAccess();
	}

}

The User class has a userName, level and a reference to the AccessControl assigned to it.


 
We have used an AccessControlProvider class that creates and stores the possible AccessControl objects in advance. And when the there’s a request to an AccessControl object, it returns a new object created by copying the stored prototypes.

package com.javacodegeeks.patterns.prototypepattern;

import java.util.HashMap;
import java.util.Map;

public class AccessControlProvider {

	private static Map<String, AccessControl>map = new HashMap<String, AccessControl>();

	static{

		System.out.println("Fetching data from external resources and creating access control objects...");
		map.put("USER", new AccessControl("USER","DO_WORK"));
		map.put("ADMIN", new AccessControl("ADMIN","ADD/REMOVE USERS"));
		map.put("MANAGER", new AccessControl("MANAGER","GENERATE/READ REPORTS"));
		map.put("VP", new AccessControl("VP","MODIFY REPORTS"));
	}

	public static AccessControl getAccessControlObject(String controlLevel){
		AccessControl ac = null;
		ac = map.get(controlLevel);
		if(ac!=null){
			return ac.clone();
		}
		return null;
	}
}

The getAccessControlObject method fetches a stored prototype object according to the controlLevel passed to it, from the map and returns a newly created cloned object to the client code.

Now, let’s test the code.

package com.javacodegeeks.patterns.prototypepattern;

public class TestPrototypePattern {

	public static void main(String[] args) {
		AccessControl userAccessControl = AccessControlProvider.getAccessControlObject("USER");
		User user = new User("User A", "USER Level", userAccessControl);

		System.out.println("************************************");
		System.out.println(user);

		userAccessControl = AccessControlProvider.getAccessControlObject("USER");
		user = new User("User B", "USER Level", userAccessControl);
		System.out.println("Changing access control of: "+user.getUserName());
		user.getAccessControl().setAccess("READ REPORTS");
		System.out.println(user);

		System.out.println("************************************");

		AccessControl managerAccessControl = AccessControlProvider.getAccessControlObject("MANAGER");
		user = new User("User C", "MANAGER Level", managerAccessControl);
		System.out.println(user);
	}
}

The above code will produce the following output:

Fetching data from external resources and creating access control objects...
************************************
Name: User A, Level: USER Level, Access Control Level:USER, Access: DO_WORK
Changing access of: User B
Name: User B, Level: USER Level, Access Control Level:USER, Access: READ REPORTS
************************************
Name: User C, Level: MANAGER Level, Access Control Level:MANAGER, Access: GENERATE/READ REPORTS

In the above code, we have created an AccessControl object at USER level and assigned it to User A. Then, again another AccessControl object to User B, but this time we have changed the access right of User B. And in the end, MANAGER level access control to User C.

The getAccessControlObject is used to get the new copy of the AccessControl object, and this can be clearly seen when we change the access right for User B, the access right for User A is not changed (just print the User A object again). This confirms that the clone method is working fine, as it returns the new copy of the object not a reference which points to the same object.

4. When to use the Prototype Design Pattern

Use the Prototype pattern when a system should be independent of how its products are created, composed, and represented; and

  • When the classes to instantiate are specified at run-time, for example, by dynamic loading; or
  • To avoid building a class hierarchy of factories that parallels the class hierarchy of products; or
  • When instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually, each time with the appropriate state.

5. Prototype Pattern in JDK

  • java.lang.Object#clone()
  • java.lang.Cloneable

6. Download the Source Code

This was a lesson on the Prototype Design Pattern. You may download the source code here: PrototypePattern-Project

Rohit Joshi

Rohit Joshi is a Senior Software Engineer from India. He is a Sun Certified Java Programmer and has worked on projects related to different domains. His expertise is in Core Java and J2EE technologies, but he also has good experience with front-end technologies like Javascript, JQuery, HTML5, and JQWidgets.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button