This is the sixth day of my participation in the More text Challenge. For details, see more text Challenge

Wechat official account: Xiao Lei

When efforts to a certain extent, luck from with you accidentally meet.

First, the prototype pattern

1.1 an overview of the

Today, we will learn the third type of the creator pattern in the design pattern, the prototype pattern.

As usual, go to Baidu Encyclopedia to define:

Stereotype instances are used to specify the types of objects to create, and new objects are created by copying these stereotypes.

Take an already created instance as a prototype and copy the prototype object to get multiple objects that are exactly the same as the prototype object. Similar to our CTRL + C and CTRL + V combinations. C-v method for short.

So what’s the difference between the C-V method and our new object?

What is the reason for the emergence of C-V method and the significance of its existence?

1.2 Why does c-V method appear?

To answer these questions, we need to focus on the difference between the new keyword and the prototype pattern. The prototypal pattern is characterized by cloning. The difference between new and new is that new generates objects with default property values that need to be assigned later, whereas cloning generates objects with property values copied together.

The clone () layer used by the prototype pattern operates directly on the binary data stream. The key is that it does not call the constructor, it is just a copy of the data block in memory. Therefore, as JVM performance improves and new methods are optimized, new is not necessarily slower than Clone.

Here’s a simple test:

Test a:

public class User implements Cloneable{ private String name; private Integer age; public User() { } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}Copy the code
public class UserTest { public static void main(String[] args) throws CloneNotSupportedException { User user = new User(); User. Elegantly-named setName (" Xiao ray "); user.setAge(18); Long beginTime = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { User user1 = new User(); user1.setName("leilei"); user1.setAge(3); } system.out.println ("new 100,000,000 times: "+(system.currentTimemillis () -begintime)); Long beginTime2 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { User user1 = (User) user.clone(); } system.out.println (" Clone 100 times: "+(system.currentTimemillis ()-beginTime2)); }}Copy the code

Print result:

New 100 million times: 382 clone 100 million times: 457Copy the code

In this case, it’s a simple new object and assignment object, so when constructing 100 million objects, Clone is a little slower than new. But since clone does not need to call the constructor, how does the comparison compare if we add material to a complex object?

Test 2:

public class User implements Cloneable{ private String name; private Integer age; public User() { for (int i = 0; i <10; i++) { int a=1; int b=2; int c= (int) (a*b+ Math.PI); this.name="xiaolei".concat("xiaoeli").toLowerCase(Locale.ROOT); } } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}Copy the code
public class UserTest { public static void main(String[] args) throws CloneNotSupportedException { User user = new User(); User. Elegantly-named setName (" Xiao ray "); user.setAge(18); Long beginTime = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { User user1 = new User(); user1.setName("leilei"); user1.setAge(3); } system.out.println ("new 100,000,000 times: "+(system.currentTimemillis () -begintime)); Long beginTime2 = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { User user1 = (User) user.clone(); } system.out.println (" Clone 100 times: "+(system.currentTimemillis ()-beginTime2)); }}Copy the code

Print result:

New 100 million times: 20675 clone 100 million times: 347Copy the code

Therefore, it is surprising to find that when creating complex and time-consuming objects, the effect achieved by using the prototype pattern is very ideal and can greatly improve the efficiency of object creation.

So, this is an example of why the C-V method exists.

1.3 Application scenarios of the C-V method

This type of creator pattern is used to create complex objects while still being efficient. Its application scenarios are as follows:

  • 1. Using the stereotype mode is the best choice when a large number of objects of a class are needed, because the stereotype mode is a copy of the object in memory, especially if the creation of the object is very complex.
  • 2. If the initialization of an object requires a lot of data preparation for the object or other resources, as we did in the constructor above, then the prototype pattern can be used
  • 3. When a large amount of public information and a small number of fields of an object are needed for personalized Settings, the object can also be copied by using the prototype mode for processing.

Second, prototype pattern realization

2.1 structure

The roles are as follows:

  • Abstract stereotype class: Specifies the Clone method that a concrete stereotype object must implement
  • Concrete prototype class: Implements the Clone method of the abstract prototype class, which is an object that can be assigned
  • Access class: Copy the new object using the Clone method in the concrete prototype class

2.2 Clone it to walk the construction method?

Cloning in prototype mode is divided into shallow copy and deep copy.

Shallow clone: Creates a new object whose properties are identical to those of the original object. For non-basic properties, the new object still points to the memory address of the object that the original property points to. Deep clone: When a new object is created, other objects referenced in the property are also cloned and do not point to the original object address.

The Clone () method is provided in the Java Object class to implement shallow cloning. The cloned object needs to implement the Cloneable interface.

public class User implements Cloneable{ private String name; private Integer age; Public User() {system.out.println (" generate object with constructor "); } public String getName() { return name; } public void setName(String name) { this.name = name; } @ Override protected Object clone () throws CloneNotSupportedException {System. Out. Println (" using cloning method to generate Object "); return super.clone(); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}Copy the code
public class UserTest { public static void main(String[] args) throws CloneNotSupportedException { User user = new User(); User user2 = (User) user.clone(); Println (" whether user and user2 are the same object: "+ (user==user2)); }}Copy the code

Print result:

Generate objects using the constructor. Generate objects using the clone method. Whether user and user2 are the same object: falseCopy the code

In this example, it is confirmed that Clone does not take a constructor, and that the objects generated by Clone and new are not the same.

2.3 Deep clone and Shallow clone

The generation of the previous example is essentially a shallow clone, where we add a girlFrient class to the user class. Let’s see what’s wrong with shallow cloning.

public class User implements Cloneable{ private String name; private Integer age; private GirlFrient girlFrient; Public User() {system.out.println (" generate object with constructor "); } @ Override protected Object clone () throws CloneNotSupportedException {System. Out. Println (" using cloning method to generate Object "); return super.clone(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public GirlFrient getGirlFrient() { return girlFrient; } public void setGirlFrient(GirlFrient girlFrient) { this.girlFrient = girlFrient; } @ Override public String toString () {return "User {" +" name = '" + name +' \ '+', "age =" + age + ", Girlfrient.getname () + girlfrient.getName () + '}'; }}Copy the code
public class GirlFrient { private String name; public GirlFrient() { } public String getName() { return name; } public void setName(String name) { this.name = name; }}Copy the code
public class UserTest { public static void main(String[] args) throws CloneNotSupportedException { User user = new User(); GirlFrient girlFrient = new GirlFrient(); Girlfrient.setname (" Liu Yifei "); User. Elegantly-named setName (" dog "); user.setAge(3); user.setGirlFrient(girlFrient); User user2 = (User) user.clone(); GirlFrient girlFrient1 = user2.getGirlFrient(); Girlfrient1. setName(" Jobilo "); User2. Elegantly-named setName (" cat son "); user2.setGirlFrient(girlFrient1); user2.setAge(18); System.out.println("user:"+user.toString()); System.out.println("user2:"+user2.toString()); }}Copy the code

Print result:

User: user {name =' Dog ', age =3, girlfriend name =' Qiao Biluo '} user2: user {name =' cat ', age =18, girlfriend name = qiao biluo}Copy the code

Before also tested, the new object and the clone object is not the same, obviously the user dog son girlfriend is Liu Yifei, but after cloning, actually changed the girlfriend of another object, this is obviously an unreasonable thing.

This is a shallow copy, where Java only copies the object you specify, and if there are other objects in the object you specify, it doesn’t copy it, it just references it to you and shares variables. That other people copy words, girlfriend class all point to the same, obviously do not accord with socialist values!! This is a very unsafe way, want a girlfriend to go to the new.

To solve this problem, a deep copy was created. How to implement deep copy?

Then implement it manually in the Clone method to close this loophole.

@Override
    protected Object clone() throws CloneNotSupportedException {
        User user = (User) super.clone();
        GirlFrient girlFrient = new GirlFrient();
        user.setGirlFrient(girlFrient);
        return user;
    }
Copy the code

Print result:

User: user {name =' Dog ', age =3, girlfriend name = liu Yifei} user2: user {name =' Cat ', age =18, girlfriend name = Qiao Biluo}Copy the code

That’s normal. This is a deep copy. (Cat cries….)

Third, summary

In this chapter, several examples, mainly introduced the reason for the emergence of prototype pattern and application scenarios, prototype pattern and the difference between new object, and illustrated with examples. Application scenarios of the prototype pattern, and finally the difference between shallow and deep copies in Java. This is the third design pattern in the design Patterns series. Thanks for reading. Your likes will be the best motivation for me to update.