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

  • ifaNot a concrete instance, but an abstract class or interface. Abstract classes or interfaces cannot benewWhat 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 changedaObject 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

  1. The classes being copied need to be implementedCloneableThis 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”)
  2. The copied class needs to be overwrittenObjectIn 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