Liver-Liver Design Pattern [3] -- Prototype Pattern

Series Article Directory

Liver-Liver Design Pattern [1]--Singleton Mode Portal
Liver-Liver Design Pattern [2]--Factory Mode Portal
Liver-Liver Design Pattern [3]--Prototype Mode Portal
Liver-Liver Design Pattern [4] 】--Builder mode portal
liver-to-liver design mode [5]--adapter mode portal
liver-to-liver design mode [6]--decorator mode portal
liver-to-liver design mode [7]--proxy mode transmission Portal
Liver-Liver Design Pattern [8] -- Appearance Mode Portal
Liver-Liver Design Pattern [9] -- Flyweight Mode Portal



foreword

In the previous article, we knew that design patterns can be divided into three categories: creational patterns, structural patterns, and behavioral patterns. There are 5 types of creational patterns. In the first two sections, we analyzed the singleton pattern, factory method pattern, and abstract factory pattern. Then there are two more patterns: prototype pattern and builder pattern, which are also creational patterns. This In this section we analyze the prototype pattern.


1. What is the prototype mode

Prototype Pattern (Prototype Pattern) is used to create repeated objects while ensuring performance. This type of design pattern is a creational pattern, which provides an optimal way to create objects.
The prototype pattern requires an object to implement an interface that can clone itself, so that a new instance can be created by copying an instance object itself. In this way, if you create a new object through the prototype instance, you no longer need to care about the type of the instance itself. As long as you implement the method of cloning yourself, you can use this method to obtain a new object without creating it through new.

Yes, I’m going to give an example again, the rabbit and the tiger have the same birthday (well, the goose said they have the same birthday ┐(・o・)┌ ), let me send them a congratulatory email.
insert image description here
I am lazy, except for the signature, the other contents are the same. At this time, I can write the blessing first, then clone the blessing, and finally send it according to different signatures.

Write down the code:

public class PrototypeClient {
    
    
	static class Mail implements Cloneable {
    
    
		private String name;
		private String message;
		
		public Mail() {
    
    }
        
		public String getName() {
    
    
	        return name;
	    }
	
	    public void setName(String name) {
    
    
	        this.name = name;
	    }
	    
	    public String getMessage() {
    
    
	        return message;
	    }
	
	    public void setMessage(String message) {
    
    
	        this.message = message;
	    }
	    
	    @Override
        protected Mail clone() {
    
    
            Mail cloneMail = null;
            try {
    
    
                cloneMail = (Mail) super.clone();
            } catch (CloneNotSupportedException e) {
    
    
                e.printStackTrace();
            }
            return cloneMail;
        }

        @Override
        public String toString() {
    
    
            return name + ":" + message;
        }
	}
	public static void main(String[] args) {
    
    
        Mail mail = new Mail();
        mail.setMessage("祝你生日快乐~~");
        Mail mail2 = mail.clone();
        mail.setName("兔子");
        mail2.setName("老虎");
        System.out.println(mail.toString());
        System.out.println(mail2.toString());
    }
}

We can see that the Mail class implements the Cloneable interface, and the copy of this class can be completed by rewriting the clone() method.

Let's look at the source code again and find that Cloneable is just an empty interface. The reason why JDK does this is to notify the JVM at runtime that the clone() method can be used on this class. If the class does not implement the Cloneable interface, the clone() method is called. A CloneNotSupportedException will be thrown.

In daily development, the super.clone() method cannot meet all requirements. If there is a reference object attribute in the Mail class, then the attribute of the object we cloned will point to the same memory address as the attribute of the prototype object, which extends The problem of shallow cloning and deep cloning .

2. Shallow cloning

public class PrototypeClient {
    
    
	@Data
	static class Mail implements Cloneable {
    
    
		private String name;
		private String message;
		// 我们加一个礼物List
		private List<String> gifts;
	    
	    @Override
        protected Mail clone() {
    
    
            Mail cloneMail = null;
            try {
    
    
                cloneMail = (Mail) super.clone();
            } catch (CloneNotSupportedException e) {
    
    
                e.printStackTrace();
            }
            return cloneMail;
        }

        @Override
        public String toString() {
    
    
            return name + ":" + message + ",gifts:" + gifts;
        }
	}
	public static void main(String[] args) {
    
    
        Mail mail = new Mail();
        mail.setName("兔子");
        mail.setMessage("祝你生日快乐~~");
        List<String> gifts = new ArrayList<String>();
        gifts.add("糖果");
        gifts.add("积木");
        mail.setGifts(gifts);
        
        Mail cloneMail = mail.clone();
        cloneMail.setName("老虎");
        cloneMail.getGifts().add("吉他");
        
        System.out.println(mail.toString());
        System.out.println(cloneMail.toString());
    }
}

We add an attribute gifts (gifts), and then add an element to the gifts of the cloned object, and then we find that the prototype object has also changed. We expect the cloned object to be independent of the prototype object and should not be connected, so This is obviously not as expected.

So through the above code, we can see that the clone() method that comes with Java performs shallow cloning, and all reference objects share a memory address. How to solve this problem, that is, how to perform deep cloning?
In Java, if you want to complete the deep cloning of the prototype object, you usually use the Serializable method to achieve cloning through serialization and deserialization of the object, which can realize real deep cloning.

3. Deep cloning

Continue to modify the code and add a deepClone() method

public class PrototypeClient {
    
    
	@Data
	static class Mail implements Cloneable, Serializable {
    
    
		private String name;
		private String message;
		// 我们加一个礼物List
		private List<String> gifts;
	    
	    public Mail deepClone(){
    
    
	        try {
    
    
	            ByteArrayOutputStream bos = new ByteArrayOutputStream();
	            ObjectOutputStream oos = new ObjectOutputStream(bos);
	            oos.writeObject(this);
	
	            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
	            ObjectInputStream ois = new ObjectInputStream(bis);
	
	            return (Mail)ois.readObject();
	        }catch (Exception e){
    
    
	            e.printStackTrace();
	            return null;
	        }
	    }
	    
	    @Override
        protected Mail clone() {
    
    
            Mail cloneMail = null;
            try {
    
    
                cloneMail = (Mail) super.clone();
            } catch (CloneNotSupportedException e) {
    
    
                e.printStackTrace();
            }
            return cloneMail;
        }

        @Override
        public String toString() {
    
    
            return name + ":" + message + ",gifts:" + gifts;
        }
	}
	public static void main(String[] args) {
    
    
        Mail mail = new Mail();
        mail.setName("兔子");
        mail.setMessage("祝你生日快乐~~");
        List<String> gifts = new ArrayList<String>();
        gifts.add("糖果");
        gifts.add("积木");
        mail.setGifts(gifts);
        
        // 深克隆
        Mail deepCloneMail = mail.deepClone();
        deepCloneMail.setName("老虎");
        deepCloneMail.getGifts().add("吉他");

        System.out.println(mail.toString());
        System.out.println(deepCloneMail.toString());
        System.out.println(mail == deepCloneMail);
        System.out.println(mail.getGifts() == deepCloneMail.getGifts());
    }
}

Running results:
insert image description here
Through the running results, we have successfully completed the deep clone.


write at the end

Prototype mode usage scenarios:

  • When the class initialization needs to consume a lot of resources;
  • When obtaining a database connection is cumbersome;
  • When an object has many modifiers;

Advantages of the Prototype pattern:

  • Can improve performance;

Disadvantages of prototype pattern:

  • Since the Cloneable interface must be implemented, it may be inconvenient to use.

Guess you like

Origin blog.csdn.net/u011646838/article/details/130402156