[Design Mode]-Prototype Mode

1. Introduction to the prototype mode

1. What is prototype mode

The prototype mode (prototype) is a kind of creational design mode. Usually the prototype mode is used to create objects with the same properties. It encapsulates the creation process of the object, and the business caller does not need to care about the details and principles of object creation.
The prototype mode should be the simplest of the 23 design modes, which itself has been partially implemented by the Java language, so in most cases we only need to use it.

2. The business scenario of the prototype mode application

Prototype mode is usually used to create multiple duplicates of the same object. We can understand that it is necessary to use prototype mode when realizing self-replication of objects. To give the simplest example, Monkey King in Journey to the West became thousands of Monkey Kings through monkey hair, or Naruto in Naruto split into multiple Naruto through multiple shadow clones. The prototype mode is a copy of the original entity. Means into multiple objects.

Second, the realization of the prototype mode

1. The realization principle of prototype mode

It is very simple to implement the prototype mode through the Java language. Since the Object object has its own clone method, we only need to call the clone method. It should be noted here that since the Object object itself does not implement the cloneable interface, we need to implement the cloneable interface for our prototype object before using the clone method.
Insert picture description here

2. Simple implementation of prototype mode

Here we simply simulate the realization of a Monkey King changing into a monkey grandson:

2.1 Create a prototype object

public class Monkey implements Cloneable {
    
    
	private String name;
	private String age;

	@Override
	protected Monkey clone() throws CloneNotSupportedException {
    
    
		// 这里先不修改浅拷贝相关代码
		return (Monkey) super.clone();
	}

	public Monkey(String name, String age) {
    
    
		super();
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
    
    
		return "Monkey [name=" + name + ", age=" + age + "]";
	}

}

2.2 Test prototype objects

public class Test {
    
    

	public static void main(String[] args) throws CloneNotSupportedException {
    
    
		Monkey monkey = new Monkey("孙悟空", "三百四十二岁");
		Monkey clone = monkey.clone();
		System.out.println(monkey.equals(clone));
		System.out.println(clone.toString());
	}
}

Test result:
Insert picture description here
Here we see that a new object has been created successfully, but in fact there is still a problem here, let's talk about it in detail next.

3. Problems with calling clone method directly

If we add an attribute of the reference data type to the entity at this time, will this attribute create a new object after being copied by the clone method? Here we simply modify the code, add a set of occupations, and provide him with a default assignment in the parameterized construction method.

public class Monkey implements Cloneable {
    
    
	private String name;
	private String age;
	// 职业
	private List vocation;

	@Override
	protected Monkey clone() throws CloneNotSupportedException {
    
    
		// 这里先不修改浅拷贝相关代码
		return (Monkey) super.clone();
	}

	public Monkey(String name, String age) {
    
    
		super();
		this.name = name;
		this.age = age;
		this.vocation = new ArrayList<>();
	}

	@Override
	public String toString() {
    
    
		return "Monkey [name=" + name + ", age=" + age + ", vocation=" + vocation + "]";
	}

	public List getVocation() {
    
    
		return vocation;
	}

}

Then let us observe the result

public class Test {
    
    

	public static void main(String[] args) throws CloneNotSupportedException {
    
    
		Monkey monkey = new Monkey("孙悟空", "三百四十二岁");
		Monkey clone = monkey.clone();
		System.out.println(monkey.equals(clone));
		System.out.println(clone.getVocation().equals(monkey.getVocation()));

	}
}

Insert picture description here
Here we observe that the List property in the prototype object does not reallocate an address in the cloned object, but the prototype object and the cloned object share the same memory space, which will undoubtedly cause a serious problem of variable security, causing this problem The root cause is that the clone method of Object implements shallow copy by default, and this problem occurs when shallow copy encounters a reference type.

3. Deep copy and shallow copy

1. What is deep copy and shallow copy

Shallow copy means that when we clone an object, we only copy the reference value of the object. The new object and the old object share the same memory address, so that the value in the new object is manipulated, and the old object can also be perceived . The JDK clone method defaults to a shallow copy of the implementation.
Deep copy is different from shallow copy. Deep copy creates a new memory space for the new object, and then assigns the value of the variable in the old reference object to the new object. The memory points of the new and old objects are different, and the old objects will not perceive the value of the new object.

2. How to implement a deep copy

There are two main ways to implement deep copy:

  1. Double shallow copy
  2. Serialization and deserialization

Fourth, the realization of deep copy prototype mode

1. Double shallow copy

The realization of double shallow copy is very simple, that is, by creating a prototype copy for the reference data type in the prototype class to achieve the purpose of creating a new memory reference.

Test code:

public class Monkey implements Cloneable {
    
    
	private static final String Monkey = null;
	private String name;
	private String age;
	// 职业
	private ArrayList vocation;

	@Override
	protected Monkey clone() throws CloneNotSupportedException {
    
    
		Monkey clone = (Monkey) super.clone();
		ArrayList copy = clone.getVocation();
		ArrayList shallowCopy = (ArrayList) copy.clone();
		ArrayList deepCopy = new ArrayList<>();
		deepCopy.add(shallowCopy);
		clone.setVocation(deepCopy);
		return clone;
	}

	public void setVocation(ArrayList vocation) {
    
    
		this.vocation = vocation;
	}

	public Monkey(String name, String age) {
    
    
		super();
		this.name = name;
		this.age = age;
		this.vocation = new ArrayList<String>();
		this.vocation.add("齐天大圣");
	}

	@Override
	public String toString() {
    
    
		return "Monkey [name=" + name + ", age=" + age + ", vocation=" + vocation + "]";
	}

	public ArrayList getVocation() {
    
    
		return vocation;
	}

}

operation result:

public class Test {
    
    

	public static void main(String[] args) throws CloneNotSupportedException {
    
    
		Monkey monkey = new Monkey("孙悟空", "三百四十二岁");
		Monkey clone = monkey.clone();
		System.out.println(monkey.equals(clone));
		System.out.println(clone.getVocation().equals(monkey.getVocation()));

	}
}

Insert picture description here
Here we found that although the double shallow copy method can achieve deep copy, if there are too many reference types, we need to deal with each reference type separately. The code is cumbersome and daily use is not recommended.

2. Json serialization method

There are many ways to implement serialization in Java. I usually prefer to use Json objects to achieve serialization and deserialization. Here we need to introduce a Json toolkit

public class Monkey implements Cloneable, Serializable {
    
    
	private static final String Monkey = null;
	private String name;
	private String age;
	// 职业
	private ArrayList<Object> vocation;

	@Override
	protected Monkey clone() throws CloneNotSupportedException {
    
    
		Monkey clone = (Monkey) super.clone();
		String jsonString = JSON.toJSONString(clone);
		Monkey parseObject = JSON.parseObject(jsonString, Monkey.class);
		return parseObject;

	}

	public Monkey() {
    
    
		super();
		// TODO Auto-generated constructor stub
	}

	public Monkey(String name, String age, ArrayList vocation) {
    
    
		super();
		this.name = name;
		this.age = age;
		this.vocation = vocation;
	}

	public String getName() {
    
    
		return name;
	}

	public void setName(String name) {
    
    
		this.name = name;
	}

	public String getAge() {
    
    
		return age;
	}

	public void setAge(String age) {
    
    
		this.age = age;
	}

	public ArrayList getVocation() {
    
    
		return vocation;
	}

	public void setVocation(ArrayList vocation) {
    
    
		this.vocation = vocation;
	}

	public static String getMonkey() {
    
    
		return Monkey;
	}

}

Test class:

public class Test {
    
    

	public static void main(String[] args) throws CloneNotSupportedException {
    
    
		ArrayList<Object> arrayList = new ArrayList<Object>();
		arrayList.add(new Object());
		Monkey monkey = new Monkey("孙悟空", "三百四十二岁", arrayList);
		Monkey clone = monkey.clone();
		System.out.println(monkey.equals(clone));
		System.out.println(clone.getVocation().equals(monkey.getVocation()));
		System.out.println(monkey.getVocation().hashCode());
		System.out.println(clone.getVocation().hashCode());

	}
}

Test Results:
Insert picture description here

Five, summary

1. Design Ideas of Prototype Mode

Insert picture description here

The realization idea of ​​the prototype mode is very simple:

  1. Inherit the cloneable interface
  2. Copy the clone method of the Object class
  3. The business party can call the clone method of the prototype class

2. Features of the prototype model

advantage:

  1. Improve performance and avoid constructor constraints

Disadvantages:

  1. If the class attribute contains a reference data type that requires special treatment, it is prone to errors
  2. The cloneable interface must be implemented, which increases code complexity

Okay, this concludes today's content. If you have any questions, you can privately message me or leave a message in the comment area, and I will answer you as soon as possible. Friends who feel rewarded, please remember one-click three consecutive times, pay attention to bloggers, don’t get lost, and refuse to be a prostitute~

Guess you like

Origin blog.csdn.net/xiaoai1994/article/details/112599634