Learning goals

  • Knowledge of prototype patterns and builder application scenarios
  • Master the writing method of shallow clone and deep clone of prototype mode
  • Master the basic writing of builder mode
  • Understand how cloning breaks singletons
  • Understand the pros and cons of prototyping patterns
  • Learn the difference between builder mode and factory mode

Definition of archetypal patterns

  • A Prototype Pattern is an instance of a Prototype that specifies the type of object to create and that is innovated by copying those prototypes.
  • The caller does not need to know any creation details and does not call the constructor
  • Belongs to the creation mode

The application scenario of the prototype pattern

  • Class initialization consumes many resources
  • An object produced by new requires a very tedious process (data preparation, access rights, etc.)
  • Constructors are more complex
  • When a large number of objects are produced in a loop body

Application in the Prototype Java JDK

  • ArrayList
  • HashMap

Advantages of the prototype pattern

  • Excellent performance. Java’s own prototype mode is based on the copy of in-memory binary stream, which is much better than directly new an object
  • You can store the state of an object using deep cloning. You can use prototype mode to make a copy of an object and store its state, simplifying the creation process and eliminating the need to repeatedly set parameters through constructors or get\set methods

Disadvantages of the prototype pattern

  • Clone (or copiable) methods must be equipped
  • When modifying an existing class, you need to modify the code, which violates the open close principle
  • Deep copy and shallow copy must be used properly
  • Use of stereotype and singleton requirements separately (a class cannot be both a singleton and a stereotype)

The difference between deep clone and shallow clone

  • A deep clone copies values
  • Shallow clones copy references

The prototype

  • example

A prototype object

import lombok.Data; @Data public class ExamPaper{ private String examinationPaperId; // Private String leavTime; Private String organizationId; Private String ID; Private String examRoomId; Private String userId; Private String specialtyCode; // Private String postionCode; Private String gradeCode; Private String examStartTime; // Test start time private String examEndTime; Private String singleSelectionImpCount; Private String multiSelectionImpCount; Private String judgementImpCount; // Private String examTime; Private String fullScore; // Private String passScore; // private String userName; // Private String score; Private String resut; Private String singleOkCount; Private String multiOkCount; // Number of multiple choice questions answered private String judgementOkCount; Public ExamPaper copy(){ExamPaper ExamPaper = new ExamPaper(); Exampaper.setleavtime (this.getleavtime ()); // Exampaper.setleavtime (this.getleavtime ()); / / unit of the primary key examPaper. SetOrganizationId (enclosing getOrganizationId ()); // exampaper.setid (this.getid ()); // Exampaper.setUserId (this.getUserId()); / / professional examPaper. SetSpecialtyCode (enclosing getSpecialtyCode ()); / / post examPaper. SetPostionCode (enclosing getPostionCode ()); / / level examPaper. SetGradeCode (enclosing getGradeCode ()); / / start time examPaper exam. SetExamStartTime (enclosing getExamStartTime ()); Exampaper.setexamendtime (this.getExamendTime ()); / / single topic selection important quantity examPaper. SetSingleSelectionImpCount (enclosing getSingleSelectionImpCount ()); / / multiple choice important quantity examPaper. SetMultiSelectionImpCount (enclosing getMultiSelectionImpCount ()); / / determine the topic important quantity examPaper. SetJudgementImpCount (enclosing getJudgementImpCount ()); Exampaper.setexamtime (this.getexamtime ())); // Exampaper.setexamtime (this.getexamtime ()); / / total examPaper. SetFullScore (enclosing getFullScore ()); Exampaper.setpassscore (this.getPassScore())); Exampaper.setusername (this.getUsername ())); / / score examPaper. SetScore (enclosing getScore ()); / / radio right quantity examPaper. SetSingleOkCount (enclosing getSingleOkCount ()); / / a multiple-choice answer number examPaper. SetMultiOkCount (enclosing getMultiOkCount ()); / / judgment right quantity examPaper. SetJudgementOkCount (enclosing getJudgementOkCount ()); return examPaper; } @Override public String toString() { return "ExamPaper{" + "examinationPaperId='" + examinationPaperId + '\'' + ", leavTime='" + leavTime + '\'' + ", organizationId='" + organizationId + '\'' + ", id='" + id + '\'' + ", examRoomId='" + examRoomId + '\'' + ", userId='" + userId + '\'' + ", specialtyCode='" + specialtyCode + '\'' + ", postionCode='" + postionCode + '\'' + ", gradeCode='" + gradeCode + '\'' + ", examStartTime='" + examStartTime + '\'' + ", examEndTime='" + examEndTime + '\'' + ", singleSelectionImpCount='" + singleSelectionImpCount + '\'' + ", multiSelectionImpCount='" + multiSelectionImpCount + '\'' + ", judgementImpCount='" + judgementImpCount + '\'' + ", examTime='" + examTime + '\'' + ", fullScore='" + fullScore + '\'' + ", passScore='" + passScore + '\'' + ", userName='" + userName + '\'' + ", score='" + score + '\'' + ", resut='" + resut + '\'' + ", singleOkCount='" + singleOkCount + '\'' + ", multiOkCount='" + multiOkCount + '\'' + ", judgementOkCount='" + judgementOkCount + '\'' + '}'; }}Copy the code

BeanUtils copies objects because they have a lot of properties and uses reflection to assign values.

import java.lang.reflect.Field; public class BeanUtils { public static Object copy(Object protorype) { Class clazz = protorype.getClass(); Object returnValue = null; try { returnValue = clazz.newInstance(); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); field.set(returnValue, field.get(protorype)); } }catch (Exception e){ e.printStackTrace(); } return returnValue; }}Copy the code

Client testing

public class Client { public static void main(String[] args) { // ExamPaper examPaper = new ExamPaper(); // System.out.println(examPaper); ExamPaper examPaper = (ExamPaper)BeanUtils.copy(new ExamPaper()); System.out.println(examPaper); }}Copy the code

First, shallow clone

  • Conclusion: Hobbies refer to data types, shallow clones that copy prototype object values. They are the same reference and do not generate new objects
@Data public class ConcretePrototype implements Cloneable { private int age; private String name; private List<String> hobbies; @Override public ConcretePrototype clone() { try { return (ConcretePrototype) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } @Override public String toString() { return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + ", hobbies=" + hobbies + '}'; }}Copy the code
Public Class Client {public static void main(String[] args) {// ConcretePrototype prototype = new ConcretePrototype(); prototype.setAge(18); prototype.setName("Lisa"); List<String> hobbies = new ArrayList<>(); Hobbies. Add (" music "); Hobbies. Add (" fine arts "); prototype.setHobbies(hobbies); ConcretePrototype cloneType = prototype.clone(); CloneType. GetHobbies (). The add (" basketball "); System.out.println(" prototype: "+ prototype); System.out.println(" clone object: "+ cloneType); System.out.println(prototype == cloneType); System.out.println(" prototype.gethobbies () "); Println (" clone object hobby: "+ clonetype.gethobbies ()); System.out.println(prototype.getHobbies() == cloneType.getHobbies()); }}Copy the code

Second, deep cloning

@Data public class ConcretePrototype implements Cloneable,Serializable { private int age; private String name; private List<String> hobbies; @Override public ConcretePrototype clone() { try { return (ConcretePrototype) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } public ConcretePrototype 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 (ConcretePrototype) ois.readObject(); } catch (Exception e) { e.printStackTrace(); return null; } } @Override public String toString() { return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + ", hobbies=" + hobbies + '}'; }}Copy the code
import java.util.ArrayList; import java.util.List; Public Class Client {public static void main(String[] args) {// ConcretePrototype prototype = new ConcretePrototype(); prototype.setAge(18); prototype.setName("Lisa"); List<String> hobbies = new ArrayList<>(); Hobbies. Add (" music "); Hobbies. Add (" fine arts "); prototype.setHobbies(hobbies); // ConcretePrototype cloneType = prototype. DeepClone (); CloneType. GetHobbies (). The add (" basketball "); System.out.println(" prototype: "+ prototype); System.out.println(" clone object: "+ cloneType); System.out.println(prototype == cloneType); System.out.println(" prototype.gethobbies () "); Println (" clone object hobby: "+ clonetype.gethobbies ()); System.out.println(prototype.getHobbies() == cloneType.getHobbies()); }}Copy the code

Execution Result:

The singleton

import lombok.Data; import java.util.List; @Data public class ConcretePrototype implements Cloneable { private int age; private String name; private List<String> hobbies; private static ConcretePrototype instance = new ConcretePrototype(); private ConcretePrototype(){} public static ConcretePrototype getInstance(){ return instance; } @Override public ConcretePrototype clone() { try { return (ConcretePrototype) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } @Override public String toString() { return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + ", hobbies=" + hobbies + '}'; }}Copy the code
import java.util.ArrayList; import java.util.List; Public Class Client {public static void main(String[] args) {// ConcretePrototype prototype = ConcretePrototype.getInstance(); prototype.setAge(18); prototype.setName("Lisa"); List<String> hobbies = new ArrayList<>(); Hobbies. Add (" music "); Hobbies. Add (" fine arts "); prototype.setHobbies(hobbies); ConcretePrototype cloneType = prototype.clone(); CloneType. GetHobbies (). The add (" basketball "); System.out.println(" prototype: "+ prototype); System.out.println(" clone object: "+ cloneType); System.out.println(prototype == cloneType); System.out.println(" prototype.gethobbies () "); Println (" clone object hobby: "+ clonetype.gethobbies ()); System.out.println(prototype.getHobbies() == cloneType.getHobbies()); }}Copy the code

  • Do not implement the Cloneable interface if it is singleton mode
  • If implemented, the clone method is as follows
@Override
public ConcretePrototype clone() {
    return instance;
}
Copy the code
  • The stereotype and singleton patterns conflict and you can only choose one or the other