Design pattern prototype pattern

Archetypal model

Basic introduction

  1. Prototype mode refers to: using prototype instances to specify the type of objects to be created, and copying these prototypes to create new objects.
  2. Prototype pattern is a kind of creative design pattern, which allows one object to create another customizable object without knowing how to create details.
  3. How it works: by passing a prototype object to the object to be created, the object to be created is created by requesting the prototype object to copy itself, i.e. object. clone()
  4. Generating an object through new requires a very cumbersome data preparation or access right, so prototype mode can be used.
  5. Cloning is similar to new, but different from new. New creates new object properties with default values. The property value of the cloned object is exactly the same as that of the prototype object. And the change of the cloned new object will not affect the prototype object. Then, change the value of the cloned object

PS: pay attention to the words: Clone and copy are the same thing!

Prototype pattern UML class diagram

Explain

  1. Prototype: a prototype class that declares an interface to clone itself
  2. ConcretePrototype: a concrete prototype class that implements a clone operation
  3. Client: let a prototype object clone itself to create a new object (same property)

Case analysis

The core of the prototype pattern is cloning, so here's an example of cloning sheep.

Cloning in traditional way

code implementation

//These two notes are lombok's
@Data 
@AllArgsConstructor //All parameter constructor
public class Sheep {
	private String name;
	private int age;
	private String color;
}

//Client
public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//Traditional approach
		Sheep sheep = new Sheep("tom", 1, "white");
		
		Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
		Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
		Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
		Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
		//....
		
		System.out.println(sheep);
		System.out.println(sheep2);
		System.out.println(sheep3);
		System.out.println(sheep4);
		System.out.println(sheep5);
		//...
	}

}

Analysis

Advantage

It is easy to understand and operate.

shortcoming
  1. When creating a new object, it is always necessary to retrieve the properties of the original object. If the created object is complex, the efficiency is low
  2. It is always necessary to reinitialize the object instead of dynamically obtaining the state of the object at runtime, which is not flexible enough
Improvement thinking

In Java, the Object class is the root class of all classes. The Object class provides a clone() method, which can copy a Java Object, but the Java class that needs to implement clone must implement an interface clonable, which means that the class can copy and has the ability to copy = > prototype mode

Prototype mode - light copy

Introduction to shallow copy

  1. For a member variable whose data type is the basic data type, the shallow copy will directly transfer the value, that is, copy the attribute value to a new object.
  2. For a member variable whose data type refers to a data type, such as an array or a class object, the shallow copy will transfer the reference, that is, copy the reference value (memory address) of the member variable to a new object. Because in fact, this member variable of both objects points to the same instance. In this case, modifying the member variable in one object affects the value of the member variable in another object
  3. Shallow copy is implemented using the default clone() method

code implementation

@Data 
@AllArgsConstructor //All parameter constructor
public class Sheep implements Cloneable {
	private String name;
	private int age;
	private String color;
	//Property is an object, how is cloning handled? The default is shallow copy
	public Sheep friend; 
	
	//Clone the instance and use the default clone method to complete
	@Override
	protected Object clone()  {
		Sheep sheep = null;
		try {
			sheep = (Sheep)super.clone();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return sheep;
	}
}

//Client
public class Client {

	public static void main(String[] args) {
		System.out.println("Prototype pattern completes object creation");
		Sheep sheep = new Sheep("tom", 1, "white");
		
		sheep.friend = new Sheep("jack", 2, "black");
		
		Sheep sheep2 = (Sheep)sheep.clone(); //Clone
		Sheep sheep3 = (Sheep)sheep.clone(); //Clone
		Sheep sheep4 = (Sheep)sheep.clone(); //Clone
		Sheep sheep5 = (Sheep)sheep.clone(); //Clone
		
		System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());
		System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());
		System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());
		System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());
	}

}

The output sheep.friend.hashCode() is the same, and the member variable of reference type does not realize the real copy.

Analysis

Because the prototype pattern of the shallow copy implementation is used to create the object instance. The name, age and color attributes of the sheet class can be copied directly, and the objects do not affect each other. However, friend is the object of the class, not the basic data type, but the reference data type, so the copy only points to the same address, so if a change is made, the friend attributes of all copied objects will be changed.
In order to make the member variables of non basic data types copy into new objects, we need to adopt the way of deep copy to realize the prototype pattern.

shortcoming

All variables of the copied object contain the same value as the original object, and all references to other objects still point to the original object.

Prototype mode - deep copy

Basic introduction to deep copy

  1. Copy member variable values for all basic data types of an object
  2. Apply storage space for all member variables of reference data type, and copy the object referenced by each member variable of reference data type until all the objects that the object can reach. That is to say, to make a deep copy of an object, you need to copy the entire object (including the reference type of the object)

Implementation of deep copy

  1. Rewrite clone method to realize deep copy
  2. Deep copy through object serialization (recommended)
Deep and shallow clone map comparison

code implementation

//Object instance being copied in depth
@Data 
@AllArgsConstructor //All parameter constructor
public class DeepCloneableTarget implements Serializable, Cloneable {
	private String cloneName;
	private String cloneClass;

	//Because the properties of this class are all strings, we can use the default clone here to complete
	@Override
	protected Object clone() throws CloneNotSupportedException { 
		return super.clone();
	}
}

//Classes with deep copy
public class DeepProtoType implements Serializable, Cloneable{
	//String property (basic data type)
	public String name; 
	// reference type
	public DeepCloneableTarget deepCloneableTarget;
	
	public DeepProtoType() {
		super();
	}
	
	//Deep copy mode 1 rewrite clone method
	//For member variables of reference type, clone them separately again
	@Override
	protected Object clone() throws CloneNotSupportedException {
		
		Object deep = null;
		//The basic data types (properties) and strings are cloned here
		deep = super.clone(); 
		
		//For properties of reference types, handle them separately
		DeepProtoType deepProtoType = (DeepProtoType)deep;
		deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();

		return deepProtoType;
	}
	
	//Deep copy - mode 2 is implemented by serializing objects (recommended)
	public Object deepClone() {
		
		//Create a flow object
		ByteArrayOutputStream bos = null;
		ObjectOutputStream oos = null;
		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		
		try {
			//serialize
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(this); //This object is currently output as an object stream
			
			//De serialization
			bis = new ByteArrayInputStream(bos.toByteArray());
			ois = new ObjectInputStream(bis);
			DeepProtoType copyObj = (DeepProtoType)ois.readObject();
			
			return copyObj;
			
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return null;
		} finally {
			//Closed flow
			try {
				bos.close();
				oos.close();
				bis.close();
				ois.close();
			} catch (Exception e2) {
				// TODO: handle exception
				System.out.println(e2.getMessage());
			}
		}
		
	}
}

public class Client {

	public static void main(String[] args) throws Exception {
		DeepProtoType p = new DeepProtoType();
		p.name = "Song Jiang";
		p.deepCloneableTarget = new DeepCloneableTarget("Daniel", "Calf");
		
		//Mode 1 complete deep copy
		
		DeepProtoType p2 = (DeepProtoType) p.clone();
		
		System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
		System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
	
		//Mode 2 complete deep copy
		DeepProtoType p3 = (DeepProtoType) p.deepClone();
		
		System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
		System.out.println("p3.name=" + p.name + "p3.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
	
	}

}

Notes and details of prototype pattern

  1. When creating new objects is more complex, prototype pattern can be used to simplify the process of creating objects and improve efficiency
  2. Instead of reinitializing an object, you dynamically get the state of the object at runtime
  3. If the original object changes (increase or decrease attributes), other cloned objects will change accordingly, without modifying the code
  4. More complex code may be required for deep cloning
  5. Disadvantages: each class needs to be equipped with a clone method, which is not difficult for a new class. However, when modifying an existing class, you need to modify its source code, which violates the ocp principle. Please pay attention to this

Application scenarios in development

  1. Prototype patterns rarely appear alone, usually with factory method patterns, through clone
    The factory method creates an object, which is then provided to the caller.
  2. There are two kinds of bean creation in spring: Singleton pattern and prototype pattern. (of course, the prototype pattern needs to be matched with the factory pattern.)
Published 25 original articles, won praise 17, visited 4870
Private letter follow

Keywords: Java Lombok Attribute Spring

Added by kutchbhi on Sun, 15 Mar 2020 06:21:49 +0200