This is the 13th day of my participation in the Novembermore Challenge.The final text challenge in 2021

preface

  1. There is a problem that causes the prototype pattern: now there is a sheep Tom whose surname is Tom, age is: 1 and color is white. Please write a program to create 10 sheep with the same attributes as Tom.
  2. Sheep code:
public class sheep {
	private String name;
	private int age;
	private String color;
	public sheep(String name, int age, String color) {
		super(a);this.name = name;
		this.age = age;
		this.color = color;
	}
	/ * * *@return name
	 */
	public String getName(a) {
		return name;
	}
	/ * * *@paramName Name to be set
	public void setName(String name) {
		this.name = name;
	}
	/ * * *@return age
	 */
	public int getAge(a) {
		return age;
	}
	/ * * *@paramAge Indicates the age */
	public void setAge(int age) {
		this.age = age;
	}
	/ * * *@return color
	 */
	public String getColor(a) {
		return color;
	}
	/ * * *@paramColor Specifies the color */ to set
	public void setColor(String color) {
		this.color = color;
	}
	/* (non-javadoc) * @see java.lang.object #toString() */
	@Override
	public String toString(a) {
		return "sheep [name=" + name + ", age=" + age + ", color=" + color + "]"; }}Copy the code

Traditional way to solve

  1. Create 10 objects directly
public class client {

	public static void main(String[] args) {
		// The traditional way
				sheep sheep1 = new sheep("tom".1."White");
				
				sheep sheep2 = new sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
				sheep sheep3 = new sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
				sheep sheep4 = new sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
				sheep sheep5 = new sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor());
				//....System.out.println(sheep1); System.out.println(sheep2); System.out.println(sheep3); System.out.println(sheep4); System.out.println(sheep5); }}Copy the code
  1. Advantages and disadvantages analysis:
    • Advantage is relatively easy to understand, simple and easy to operate.
    • When creating a new object, it is always necessary to retrieve the properties of the original object. It is inefficient to create a complex object
    • It is not flexible to always need to reinitialize an object rather than dynamically obtain its runtime state
  2. Improvement idea:
    • The Object class, the root of all classes in Java, provides a clone() method that makes a copy of a Java Object, However, Java classes that need to implement clone must implement an interface Cloneable, which indicates that the class can be copied and has the power of replication => prototype mode

The prototype pattern

  1. Introduction:

    • The Prototype pattern specifies the type of object to create with Prototype instances and creates new objects by copying those prototypes
    • The prototype pattern is a creative design pattern that allows one object to create another customizable object without knowing the details of how to create it, right
    • The way it works is by passing a prototype object to the object to be created, and the object to be created performs the creation by asking the prototype objects to copy themselves, the objects.
  2. Class diagram:

    • Prototype: a Prototype class that declares an interface that clones itself
    • ConcretePrototype: ConcretePrototype class that implements an operation that clones itself
    • Client: Lets a prototype object clone itself, thus creating a new object property like this

3. Improved code:

  • First implement the sheep Cloneable, then rewrite the Clone method
public class Sheep1 implements Cloneable{
	private String name;
	private int age;
	private String color;
	public Sheep1 friend;
	
	public Sheep1(String name, int age, String color) {
		super(a);this.name = name;
		this.age = age;
		this.color = color;
	}
	/ * * *@return name
	 */
	public String getName(a) {
		return name;
	}
	/ * * *@paramName Name to be set
	public void setName(String name) {
		this.name = name;
	}
	/ * * *@return age
	 */
	public int getAge(a) {
		return age;
	}
	/ * * *@paramAge Indicates the age */
	public void setAge(int age) {
		this.age = age;
	}
	/ * * *@return color
	 */
	public String getColor(a) {
		return color;
	}
	/ * * *@paramColor Specifies the color */ to set
	public void setColor(String color) {
		this.color = color;
	}
	/* (non-javadoc) * @see java.lang.object #toString() */
	@Override
	public String toString(a) {
		return "sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
	}
	
	@Override
	public Object clone(a) {
		Sheep1 sheep = null;
		try {
			sheep = (Sheep1)super.clone();
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println(e.getMessage());
		}
		// TODO Auto-generated method stub
		returnsheep; }}Copy the code
  • Modify the Client code
System.out.println("Prototype mode completes object creation");
		// TODO Auto-generated method stub
		Sheep1 sheep = new Sheep1("tom".1."White");
		
		sheep.friend = new Sheep1("jack".2."Black");
		
		Sheep1 sheep2 = (Sheep1)sheep.clone(); / / clone
		Sheep1 sheep3 = (Sheep1)sheep.clone(); / / clone
		Sheep1 sheep4 = (Sheep1)sheep.clone(); / / clone
		Sheep1 sheep5 = (Sheep1)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());

Copy the code
  • Results:

Discuss shallow and deep copies in depth

Shallow copy

  • For member variables whose data type is a primitive data type, the shallow copy directly passes the value, that is, copies the property value to the new object.
  • For a member variable whose data type is a reference to a data type, such as an array, an object of a class, etc., shallow copy passes by reference, which simply copies the reference value (memory address) of the member variable to the new object. Because the member variable of both objects actually refers to the same instance. In this case, modifying the member variable in one object affects the value of the member variable in the other object
  • Before we clone sheep is a shallow copy
  • Shallow copy is implemented using the clone() method implicitly: sheep = (sheep) super.clone ();

Deep copy

  • Copy the member variable values of all the base data types of the object
  • Allocates storage space for all member variables that reference data types, and copies the objects referenced by each member variable of reference data types until the objects are reachable. That is, to make a deep copy of an object, the entire object is copied
  • Deep copy implementation method 1: Clone method to achieve deep copy
public class DeepProtoType implements Serializable.Cloneable{
	
	public String name; / / String attribute
	public DeepCloneableTarget deepCloneableTarget;// Reference type
	public DeepProtoType(a) {
		super(a); }// Deep copy - Mode 1 Use the clone method
	@Override
	protected Object clone(a) throws CloneNotSupportedException {
		
		Object deep = null;
		// The basic data types (attributes) and strings are cloned
		deep = super.clone(); 
		// Handle attributes of the reference type separately
		DeepProtoType deepProtoType = (DeepProtoType)deep;
		deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();
		
		// TODO Auto-generated method stub
		returndeepProtoType; }}Copy the code
  • Deep copy implementation 2: Implements the deep copy recommendation through object serialization
public class DeepProtoType implements Serializable.Cloneable{
	
	public String name; / / String attribute
	public DeepCloneableTarget deepCloneableTarget;// Reference type
	public DeepProtoType(a) {
		super(a); }// Deep copy - Approach 2 via object serialization (recommended)
	
	public Object deepClone(a) {
		
		// Create a stream object
		ByteArrayOutputStream bos = null;
		ObjectOutputStream oos = null;
		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		
		try {
			
			/ / the serialization
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(this); // The current object is output as a stream of objects
			
			// deserialize
			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 {
			/ / close the flow
			try {
				bos.close();
				oos.close();
				bis.close();
				ois.close();
			} catch (Exception e2) {
				// TODO: handle exceptionSystem.out.println(e2.getMessage()); }}}}Copy the code

Summary of prototype patterns

  • When creating a new object is complicated, the prototype pattern can be used to simplify the object creation process and improve efficiency
  • Instead of reinitializing the object, you dynamically get the run-time state of the object
  • If the original object changes (adding or subtracting attributes), the other clones will change accordingly without changing the code
  • The implementation of procloning may require more complex code
  • Disadvantages: You need to have a clone method for each class, which is not too difficult for a brand new class, but modifying an existing class requires modifying its source code, which violates THE OCP principle.