The prototype pattern of design patterns in source code -- Deep cloning and shallow cloning

๐ŸŒฒ This article is included in the column Design patterns in source code ——Perfect combination of theory and Practice

Recommended by other high-quality columns:

๐Ÿ“šTechnical expert cultivation ——Engage in technology, enter big factories and talk about the three in one column of life

๐Ÿ“šleetcode 300 questions ——An algorithm problem every day is necessary for entering a large factory

๐Ÿ“šConfused algorithm ——From today on, we have crossed the barrier of data structure and algorithm

๐Ÿ“šLearning python from actual combat ——Python crawler, automation, AI and other practical applications

Click to jump to the end of the text Receive fan benefits

Hello, everyone, I'm one~

The previous vernacular design pattern was shelved because of its work. Now it sets sail again and is eaten together with the framework source code analysis, which perfectly combines theory with practice.

Students who are not very familiar with design patterns can have a look first One sentence popular interpretation of 23 design patterns Have a comprehensive understanding of the design pattern, form an overall framework, and then break it one by one.

Today, let's take a look at the prototype pattern, which is a simple and commonly used one.

definition

Official definition

Specify the type of object to be created with the prototype instance, and create a new object by copying the prototype.

Popular interpretation

When duplicate objects need to be created, in order to ensure performance, the ontology provides an external clone for use.

Similar to printing in China, the process of new is omitted and objects are created by copy.

Structure diagram

code implementation

directory structure

It is recommended that all partners who learn design patterns build a maven project and install lombok dependencies and plug-ins.

The following package directory is established to facilitate induction and sorting.

pom is as follows

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>

Development scenario

Suppose a framework called YitiaoBatis is developed to replace Mybatis. Each time the database is operated, many records are found from the database, but few changes are made. If you check the database every time and encapsulate all the data into an object, it will lead to new and many duplicate objects, resulting in a waste of resources.

A solution is to save the checked data, check the same data, and directly return the saved objects, that is, the idea of caching.

Let's use code to simulate:

1. Create Yitiao entity class

/**
 * author:One
 */
@Data
@AllArgsConstructor
public class Yitiao {
    
    private String name;
    private Integer id;
    private String wechat;

    public Yitiao(){
        System.out.println("Yitiao objects creating");
    }
}

2. Create YitiaoBatis class

/**
 * author:One
 */
public class YitiaoBatis {
    //Cache Map    
    private Map<String,Yitiao> yitiaoCache = new HashMap<>();

    //Fetch object from cache
    public Yitiao getYitiao(String name){
        //Determine whether there is in the cache
        if (yitiaoCache.containsKey(name)){
            Yitiao yitiao = yitiaoCache.get(name);
            System.out.println("Data found from cache:"+yitiao);
            return yitiao;
        }else {
            //Simulate querying data from database
            Yitiao yitiao = new Yitiao();
            yitiao.setName(name);
            yitiao.setId(1);
            yitiao.setWechat("Official account: one coding");
            System.out.println("Find data from database:"+yitiao);
            //Put in cache
            yitiaoCache.put(name,yitiao);
            return yitiao;
        }
    }
}

3. Write test class

/**
 * author:One
 */
public class MainTest {
    public static void main(String[] args) {
        YitiaoBatis yitiaoBatis = new YitiaoBatis();
        Yitiao yitiao1 = yitiaoBatis.getYitiao("yitiao");
        System.out.println("First query:"+yitiao1);
        Yitiao yitiao2 = yitiaoBatis.getYitiao("yitiao");
        System.out.println("Second query:"+yitiao2);
    }
}

Output results

The results show that:

  • The object is created once, which is a bit of a singleton
  • The first time from the database, the second time from the cache

It seems to realize the requirements of YitiaoBatis framework. Think about it ๐Ÿค” What's the problem?

4. Modify object id

Continue writing in the test class

//Perform subsequent business and modify id
yitiao2.setId(100);

Yitiao yitiao3 = yitiaoBatis.getYitiao("yitiao");
System.out.println("Third query:"+yitiao3);

Output results

Focus on the third query, id=100?

The data we modify in memory causes the data found from the database to change, resulting in dirty data.

How to solve it? The prototype mode officially began.

5. Implement clonable interface

The ontology provides an external clone for use. The objects obtained in the cache are not returned directly, but copied, so as to ensure that the cache will not be dirty.

public class Yitiao implements Cloneable{
  
  	//......
  
		@Override
    protected Object clone() throws CloneNotSupportedException {
				return (Yitiao) super.clone();
    }
}

Modify cache

//Fetch object from cache
    public Yitiao getYitiao(String name) throws CloneNotSupportedException {
        //Determine whether there is in the cache
        if (yitiaoCache.containsKey(name)){
            Yitiao yitiao = yitiaoCache.get(name);
            System.out.println("Data found from cache:"+yitiao);
            //Modify return
            //return yitiao;
            return yitiao.clone();
        }else {
            //Simulate querying data from database
            Yitiao yitiao = new Yitiao();
            yitiao.setName(name);
            yitiao.setId(1);
            yitiao.setWechat("Official account: one coding");
            System.out.println("Find data from database:"+yitiao);
            //Put in cache
            yitiaoCache.put(name,yitiao);
            //Modify return
            //return yitiao;
            return yitiao.clone();
        }

6. Retest

Do not change the test class, just look at the results:

It can be seen from the output result that the id of the third query is still 1, and there is no dirty cache.

As like as two peas, I can get the clone exactly the same as the ontology, and the object is only new once.

I wonder if you are curious about how objects are created. Let's take a look at "deep copy" and "shallow copy".

Deep and shallow copies

definition

Deep copy: whether the copied object is a basic data type or a reference data type, it is completely copied to the new object.

Shallow copy: when the copied object contains only simple data types, such as int, float or immutable objects (strings), these fields are directly copied to the new object. Instead of copying the referenced object, the address of the referenced object is copied to the cloned object.

Like two brothers, deep copy had a very good relationship when they were young. They bought the same clothes and lived in the same house. Shallow copies are all married when they grow up. They can continue to buy the same clothes, but the house must be separated.

realization

The way to distinguish between deep copy and shallow copy in code is to see whether the value of the variable of reference type changes after modification.

Shallow copy

1. Shallow copy via clone()

Create a new Age class as the reference property of Yitiao

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Age {
    private int age;
}

2. Test 1

public static void main(String[] args) throws CloneNotSupportedException {
        Yitiao yitiao1 = new Yitiao();
        Age age = new Age(1);
        yitiao1.setAge(age);
        yitiao1.setId(1);
        Yitiao clone = yitiao1.clone();
        yitiao1.setId(2);
        age.setAge(2);    //Cannot new an age
        System.out.println("yitiao1:\n"+yitiao1+"\nclone:\n"+clone);
    }

Output results

Conclusion: the basic type id does not change. The value of the reference type Age changes because the address points to the same object.

3. Shallow copy through construction method

Yitiao.class add construction method

    public Yitiao(Yitiao yitiao){
        id=yitiao.id;
        age=yitiao.age;
    }

4. Test 2

        Yitiao yitiao1 = new Yitiao();
        Age age = new Age(1);
        yitiao1.setAge(age);
        yitiao1.setId(1);
        Yitiao clone = new Yitiao(yitiao1);  //The difference is here
        yitiao1.setId(2);
        age.setAge(2);
        System.out.println("yitiao1:\n"+yitiao1+"\nclone:\n"+clone);

Output results

Same as test 1

Deep copy

1. Implement deep copy through object serialization

Deep copy can also be achieved by calling clone method through hierarchy, but the amount of code is too large. Especially for classes with a large number of attributes and deep levels, it is too cumbersome to rewrite the clone method for each class. Generally, it is not used and no examples are given.

After the object is serialized into byte sequence, the whole object graph of the object will be serialized by default, and then the deep copy can be perfectly realized through de sequence.

Yitiao and Age implement the Serializable interface

2. Test

//Deep copy through object serialization
        Yitiao yitiao = new Yitiao();
        Age age = new Age(1);
        yitiao.setAge(age);
        yitiao.setId(1);
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(yitiao);
        oos.flush();
        ObjectInputStream ois=new ObjectInputStream(new 							ByteArrayInputStream(bos.toByteArray()));
        Yitiao clone = (Yitiao) ois.readObject();
        yitiao.setId(2);
        age.setAge(2);
        System.out.println("yitiao:\n"+yitiao+"\nclone:\n"+clone);

Output results

In conclusion, the reference object is also completely copied to a new one, and the value does not change.

However, it should be noted that if a property is modified by transient, the property cannot be copied.

Application scenario

Let's go back to prototype mode.

Prototype pattern is very common in our code, but it is easy to be ignored. For example, our commonly used BeanUtils.copyProperties is a shallow copy of objects.

See what scenarios require prototype patterns

  • resource optimization
  • Performance and safety requirements
  • A scene where one object has multiple modifiers.
  • When an object needs to be accessed by other objects, and each caller may need to modify its value, you can consider using the prototype pattern to copy multiple objects for the caller to use.

The prototype pattern has been integrated with Java and can be used easily.

summary

The prototype mode should be the simplest design mode except for a single example, but I still wrote for nearly 4 hours, drawing, typing code and writing 8000 words unconsciously.

A high-quality original article really consumes the author's efforts, so if you feel that it is well written, please give it to the third company, which is very important for one article and a driving force for creation!

last

As the old saying goes: take advantage of the wisdom of all, and you will be free; With the power of everyone, nothing is invincible. A person may walk fast, but a group of people can go further.

To this end, I made a group growth plan and shared 1-3 high-quality articles and 1 leetcode algorithm problem every day

If you are just a freshman and keep studying every day, you will read at least 4000 articles and brush 1200 questions more than others, then your salary may be 3-4 times that of others when you graduate.

If you are a professional, you can improve yourself every day, get a raise and become a technical expert.

As long as you are willing to struggle and always walk on the road of struggle, your life, the worst result, is just a late success.

Click here Join the program

If the link is blocked or there is a permission problem, it can be solved by the private chat author.

Exclusive benefits for fans

๐Ÿ“š Java: 1.5G learning materials - reply to "materials"
๐Ÿ“š Algorithm: video book - reply to "algorithm"

๐Ÿ‘‡ Click the card below Reply after concern Keywords receiving ๐Ÿ‘‡

Tags: Java Design Pattern

Posted on Tue, 21 Sep 2021 23:32:45 -0400 by wilbur