Design Mode (Java Language) - Prototype Mode

Prototype Pattern, also known as Clone Pattern, is a creative design pattern used to create duplicate objects, providing the best way to create objects.Prototype mode requires Cloneable interface to implement object cloning.In practical applications, if the application needs to create the same object repeatedly, and it takes a lot of time or access rights to create the object, such as reading the database, configuration files, etc., this is obviously not efficient if you need to read the database once every time you create a duplicate object.At this point, you can consider using prototype mode to solve the problem and improve efficiency. You only need to read the database or configuration file once when you create the prototype object, and you only need to clone one from the prototype object when you need to create the object later.In addition, the prototype mode also solves the tedious process of building complex objects. The prototype mode does not care about the details of object creation. Users only need to call the clone method to create the same object, simplifying the creation process.

Since the prototype mode has also become the cloning mode, Java cloning methods must be used in object replication.So you also need to know what shallow and deep clones are.

Shallow clone

Shallow cloning copies the properties of the basic type of object. For the properties of reference type, shallow cloning copies the address of the application type, because the application type properties of cloned object are the same memory address, that is, the same object, so when modifying this property of one object, the property of the other object will also be modified, making it easy to change the property of the other objectAttribute modifications to prototype objects are also important to note when using the prototype mode.The implementation of shallow cloning in code is relatively simple. The Java language itself already provides related interfaces and methods. We only need to inherit the Cloneable interface when using it, and override the clone method to achieve shallow cloning of objects.The code is implemented as follows:

public class Sheep implements Cloneable {

    private String name;
    private Color color = new Color();

    public Sheep() {
    }

    public Sheep(String name, String color) {
        this.name = name;

        setColor(color);
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", color=" + color +
                '}';
    }

    public Color getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color.setColor(color);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

  

public class Color implements Cloneable {

    private String color;

    public Color() {
    }

    public Color(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Color{" +
                "color='" + color + '\'' +
                '}';
    }
}

- Testing

public class Test {

public static void main(String[] args) throws CloneNotSupportedException {
Sheep test = new Sheep("test","white");
System.out.println(test);
Sheep clone = (Sheep) test.clone();
clone.setColor("black");
clone.setName("test01");
System.out.println(test);
System.out.println(clone);
}

}

When running the program, the console prints out:

Sheep{name='test', color=Color{color='white'}

Sheep{name='test', color=Color{color='black'}

Sheep{name='test01', color=Color{color='black'}

Obviously, the test object was white when it was created, then cloned with it to get a clone instance, then the color of the clone object was changed to black, the name was changed to test01, and finally the color of both objects was changed to black, confirming what was said above is that the memory address of the object was cloned for the reference type.It may be interesting to know that String is also a reference type. Why did the cloned object modify the name property but the prototype object was not modified?This is because String is final, and naturally two different memory addresses are used during cloning.

 

Deep cloning

The difference between deep cloning and shallow cloning is that when deep cloning refers to a type attribute, it copies the value of that attribute and has a different memory address from the original object, that is, two objects are different, and neither of them changes the attribute value to affect the other.There are two ways to implement deep cloning. The first way is to implement the Cloneable interface, override the clone method, and unlike shallow cloning, call the clone method with a variable of the reference type one more time.It is not recommended to use this method for deep cloning. The clone method needs to be modified every time an object's variable is modified, which violates the ocp principle.Second, using Java serialization and hair serialization is recommended.

Code implementation:

public class Color implements Cloneable, Serializable {

    private String color;

    public Color() {
    }

    public Color(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Color{" +
                "color='" + color + '\'' +
                '}';
    }
}

  

public class Sheep implements Cloneable, Serializable {

    private String name;
    private Color color = new Color();

    public Sheep() {
    }

    public Sheep(String name, String color) {
        this.name = name;

        setColor(color);
    }

    /**
     * Deep Cloning Using Serialization and Deserialization
     * @return
     */
    public Object deepClone() {
        ByteArrayInputStream bis = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);


            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return ois.readObject();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (ois != null) {
                    ois.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (oos != null) {
                    oos.close();
                }
                if (bos != null) {
                    bos.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep clone = (Sheep) super.clone();
        clone.color = (Color) clone.color.clone();
        return clone;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", color=" + color +
                '}';
    }

    public Color getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color.setColor(color);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Note that if you use Java serialization and deserialization, changing objects requires implementing the Serializable interface, otherwise a serialization exception will be thrown.

  

Summary

1. There are two implementations of prototype mode. The first is to override Cloneable's clone method by using the clone method in Object class, and call the clone method provided by Object class directly when shallow cloning.Deep cloning requires calling the clone method of the object that needs to be cloned, and of course the object must also implement the Cloneable interface.The second is to use Java's serialization and deserialization techniques, which also has the disadvantage that all variables that need to be serialized must implement the Serializable interface.

2. Advantages of prototype mode: improve efficiency; shield complex object building process and simplify code.

3. Disadvantages of the prototype model:

1) Equipping cloning methods requires a general consideration of the functionality of the class, which is not difficult for new classes, but is not necessarily easy for existing classes, especially when a class reference does not support serialization of indirect objects or when it contains a circular structure.

2) Cloneable or Serializable interfaces must be implemented.

4. Scenarios for prototype mode application:

1) Resource optimization scenarios.

2) Object initialization requires a lot of resources, including data, hardware resources, etc.

Tags: Java Database Attribute

Posted on Tue, 05 May 2020 19:31:54 -0400 by hank9481