What is a prototype pattern? Why use the prototype pattern?
Two days ago, I interviewed a little sister who graduated with a master’s degree in 1995. She worked in a big factory in Hangzhou for two years and recently wanted to return to her hometown for development
For candidates with more than two years of experience, I always ask questions related to design patterns
Let’s face it, most of the candidates don’t have a deep understanding of design patterns, and they don’t answer very well
Nor did I have high expectations when I posed these two questions to the little sister. The little sister’s answer was surprising and even gave me a deeper understanding of the prototype pattern
Why use the prototype pattern
Let’s say I have A class, let’s call it A. Class A has two attributes, x and y, and provides corresponding get and set methods for these two attributes
Take the entity object of this class, A, as an argument to the test method
Some properties of object A are required to do some business logic processing within the test method, but the original properties of object A cannot be changed
Let’s make our first attempt: declare a new object a1 and assign a to it. Let the test method use the properties of the A1 object for business logic processing
public static void test(A a) { A a1 = a; System.out.println("test method starts business logic processing "); a1.setX(1); }Copy the code
Let’s see if it affects the properties of the A object
public static void main(String[] args) { A a = new A(); a.setX(0); System.out.println(" x=" + a.gex () before calling test); test(a); System.out.println(" x=" + a.gex ()); }Copy the code
The output is
From the output, the test method changes the properties of object A and does not meet the requirements. So, the first attempt failed
We all know that the JVM allocates memory for objects after they are loaded
After loading A, allocate a space for A
When a1 is loaded, it assigns the value of A to A1, so when allocating space to A1, it only points to the memory address where A is, but does not allocate independent memory space to A1
So when you change the properties of a1, you change the properties of A
We adjust our thinking and try a second time: create a new object a2 and assign all the attributes of a to A2. The test method uses a2 objects for business logic processing
public static void test(A a) { A a2 = new A(); a2.setX(a.getX()); a2.setY(a.getY()); System.out.println("test method starts business logic processing "); a2.setX(1); a2.setY(2); }Copy the code
Let’s also verify if it affects the properties of the A object
public static void main(String[] args) { A a = new A(); a.setX(0); a.setY(0); System. The out. Println (" call test method before x = "+ al-qeada etX () +", y = "+ al-qeada etY ()); test(a); System. The out. Println (" after the call test method x = "+ al-qeada etX () +", y = "+ al-qeada etY ()); }Copy the code
The output is
The test method does not change the properties of the a object
But there’s a problem
- if
a
Not a concrete instance, but an abstract class or interface. Abstract classes or interfaces cannot benew
What should I do?
This is where the prototype pattern comes in to solve our problem
The prototype pattern
Prototype pattern definition
“Prototype mode” allows you to copy or clone an existing object without having to make your code dependent on the class the object belongs to
By definition we can extract two key pieces of information
First, the prototype pattern is mainly used to copy or clone an existing object
Second, you don’t have to rely on the class to copy the object
How do you create an object that doesn’t depend on the class it belongs to?
The answer is to leave the object creation process to this class
Prototype mode
Let’s use the prototype pattern to refine the above example
We need to know the design idea of the prototype pattern before we start
By definition, in the prototype pattern, the creation of an object is left to the class to which the object belongs, so the class must provide a method that returns the object. This is usually called clone() or copy()
Applying to class A in the example above, you need to provide A clone() method in class A that creates the current object and returns it
Clone () is used in the test method to get an A3 object to execute the business logic
public static void test(A a) { A a3 = a.clone(); System.out.println("test method starts business logic processing "); a3.setX(1); }Copy the code
Let’s see if it’s changeda
Object properties
As you can see from the output, the attributes of the A object are not changed
If A is an abstract class, how do we create this object
In fact, it is very simple, abstract classes can have abstract methods. Define the Clone () method as abstract and let subclasses implement it
Suppose A has two subclasses, SubA1 and SubA2. The two subclasses inherit the A abstract class and implement the Clone () abstract method
Use a.lone () in test to get a new object without affecting the original A object
This completes the optimization of the above example with the prototype pattern
Deep copy, shallow copy
In Java, the default Object class is the parent of all classes, with a clone() method in Object
It is a Java default method for copying objects. This method is native modified, indicating that it is a direct call to the underlying operating system. In theory, using it to copy objects will have better performance
So, we can use java.lang.object #clone() to implement the prototype pattern in two steps
- The classes being copied need to be implemented
Cloneable
This interface class. This interface class does not have any method, just play a role of a marker, can also be understood as aconvention
(“Convention is greater than Configuration”) - The copied class needs to be overwritten
Object
In theclone()
methods
So let’s optimize class A
The prototype pattern written in this way is more efficient in theory. It looks perfect, but it’s not
Let’s say class A has an ArrayList property in it
Let’s see if changing the list attribute of A4 will affect A after we clone A and get A4
The output is
When we modify the A4 object, we also change the property value of the A object, which is not the desired result
This is because: When Object is clone, it will only copy the data of the basic type. The data of reference type is not really copied, but the reference pointer points to the memory address of the data (remember the example of a and A1 pointing to the same memory address in the above example).
This behavior of copying only the underlying data type is called shallow copying. The ability to copy both the underlying data type and the behavior that refers to it is called a deep copy
In the prototype pattern, we should use deep copy to copy objects.
To implement deep copy, “the class to which the data of this reference type belongs also implements the Cloneable interface and overrides the Clone () method of Object.”
In this case, the class to which the reference type belongs is ArrayList, which itself implements the Cloneable interface and overwrites the Clone () method of the Object class.
All we need to do is call the clone() method of ArrayList in the clone() method of class A
This completes the prototype pattern based on deep copy
conclusion
Prototype pattern, also known as clone pattern, belongs to the creation pattern of the three major types of design pattern
Consider using the prototype pattern when you need to copy an object without changing the original object
When implementing the stereotype pattern, the copy of reference type data should be based on deep copy, otherwise the copied stereotype will be affected
In the Spring ecosystem, where object creation is mostly done by IOC, the prototype pattern doesn’t seem to have much use
But using less doesn’t mean it’s useless. When we learn design patterns, the purpose is not only to learn design patterns, but to learn the design ideas used by design patterns
Learn this idea, precipitation for their own ideas, in the work can be achieved by drawing inferences from one example to another, in order to go no further
— The above content is from the public account “Helian Xiaowu”, please indicate the source of reprint