prototype of JAVA design pattern

Posted by swell on Sat, 23 May 2020 18:48:08 +0200

Prototype mode:

  • Prototype mode is also called clone mode
  • Java native cloning mode
  • Cloneable must be implemented to implement clone mode
  • Interface, if not implementedJava.lang.CloneNotSupportedExceptionabnormal
  • clone mode is convenient when the properties of a class are already set and many objects with the same attribute values need to be created
  • clone mode is not necessarily better than traditional new mode
  • Shallow and Deep Clones

Looking at the code below, the Cloneable interface is not implemented

package com.srr.dp.clone;

/**
 * (Prototype Mode) Clone Mode
 */
public class Appler /*implements Cloneable*/{

    private String clor;
    private int weight;
    private int volume;
    private StringBuilder descr;

    public Appler(String clor) {
        this.clor = clor;
    }

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

    @Override
    public String toString() {
        return "Appler{" +
                "clor='" + clor + '\'' +
                ", weight=" + weight +
                ", volume=" + volume +
                ", descr=" + descr +
                '}';
    }
}

package com.srr.dp.clone;

public class T {
    public static void main(String[] args) throws CloneNotSupportedException {

        Appler appler = new Appler("yellow");

        Appler appler1 = (Appler) appler.clone();

        System.out.println(appler1);
    }
}

Run result:

 

Shallow copy:

package com.srr.dp.clone;

/**
 * (Prototype Mode) Clone Mode
 *  shallow copy
 */
public class Appler implements Cloneable {

    private String clor;
    private int weight;
    private int volume;
    private Location loc;

    public Appler(String clor,int weight,int volume,Location loc) {
        this.clor = clor;
        this.weight = weight;
        this.volume = volume;
        this.loc = loc;
    }
    public String getClor() {
        return clor;
    }

    public void setClor(String clor) {
        this.clor = clor;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public Location getLoc() {
        return loc;
    }

    public void setLoc(Location loc) {
        this.loc = loc;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //loc = (Locaton) loc.clone();
        return super.clone();
    }

    @Override
    public String toString() {
        return "Appler{" +
                "clor='" + clor + '\'' +
                ", weight=" + weight +
                ", volume=" + volume +
                ", loc=" + loc +
                '}';
    }
}

package com.srr.dp.clone;

public class Location {
    String name;
    public Location(String name){
        this.name = name;
    }

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

package com.srr.dp.clone;

/**
 * Test Code
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("Luochuan"));
        Appler appler1 = (Appler) appler.clone();
        appler.setClor("red");
        appler.getLoc().name = "Baoji";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

Run result:

 

From the results, when the appler color and the location value were changed, the color of the copied apper1 object did not change, but the location changed.

This is a shallow copy, the reference object can't guarantee that it will be completely independent after the copy. It just copies the address, but the object the address points to is shared.

Although String types are also reference types, sharing a constant pool does not cause this problem.

So how do I make the reference type independent after copying it?

For a deep copy, see the following code:

package com.srr.dp.clone;

/**
 * (Prototype Mode) Clone Mode
 *  shallow copy
 */
public class Appler implements Cloneable {

    private String clor;
    private int weight;
    private int volume;
    private Location loc;

    public Appler(String clor,int weight,int volume,Location loc) {
        this.clor = clor;
        this.weight = weight;
        this.volume = volume;
        this.loc = loc;
    }
    public String getClor() {
        return clor;
    }

    public void setClor(String clor) {
        this.clor = clor;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public Location getLoc() {
        return loc;
    }

    public void setLoc(Location loc) {
        this.loc = loc;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Appler appler = (Appler)super.clone();
        appler.loc = (Location) loc.clone();;
        return appler;
    }

    @Override
    public String toString() {
        return "Appler{" +
                "clor='" + clor + '\'' +
                ", weight=" + weight +
                ", volume=" + volume +
                ", loc=" + loc +
                '}';
    }
}

package com.srr.dp.clone;

public class Location implements Cloneable{
    String name;
    public Location(String name){
        this.name = name;
    }

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

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

package com.srr.dp.clone;

/**
 * Test Code
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("Luochuan"));
        Appler appler1 = (Appler) appler.clone();
        appler.setClor("red");
        appler.getLoc().name = "Baoji";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

Run result:

From the results, when the color of the appler and the value of location were changed, the color of the copied apper1 object did not change. The location also changed.

As mentioned above, there is no problem with shallow copies of String type, so what about StringBuilder or StringBuffer, given the length of the article, using StringBuilder as an example

Look at the code:

package com.srr.dp.clone;

/**
 * (Prototype Mode) Clone Mode
 *  shallow copy
 */
public class Appler implements Cloneable {

    private String color;
    private int weight;
    private int volume;
    private Location loc;

    public String getColor() {
        return color;
    }

    public StringBuilder getDesc() {
        return desc;
    }

    public void setDesc(StringBuilder desc) {
        this.desc = desc;
    }

    private StringBuilder desc = new StringBuilder("Yummy");

    public Appler(String color,int weight,int volume,Location loc) {
        this.color = color;
        this.weight = weight;
        this.volume = volume;
        this.loc = loc;
    }
    public String getClor() {
        return color;
    }

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

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public Location getLoc() {
        return loc;
    }

    public void setLoc(Location loc) {
        this.loc = loc;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Appler appler = (Appler)super.clone();
        appler.loc = (Location) loc.clone();
        return appler;
    }

    @Override
    public String toString() {
        return "Appler{" +
                "color='" + color + '\'' +
                ", weight=" + weight +
                ", volume=" + volume +
                ", loc=" + loc +
                ", desc=" + desc +
                '}';
    }
}

package com.srr.dp.clone;

public class Location implements Cloneable{
    String name;
    public Location(String name){
        this.name = name;
    }

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

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

package com.srr.dp.clone;

/**
 * Test Code
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("Luochuan"));
        Appler appler1 = (Appler) appler.clone();
        appler.getDesc().append("Excellent");
        appler.getLoc().name = "Baoji";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

Run result:

 

Yes, you will find that when the desc value of appler changes, the apper1 value also changes, indicating that StringBuilder copies in shallow mode, so how to achieve deep copy?

Look at the code:

package com.srr.dp.clone;

/**
 * (Prototype Mode) Clone Mode
 *  shallow copy
 */
public class Appler implements Cloneable {

    private String color;
    private int weight;
    private int volume;
    private Location loc;

    public String getColor() {
        return color;
    }

    public StringBuilder getDesc() {
        return desc;
    }

    public void setDesc(StringBuilder desc) {
        this.desc = desc;
    }

    private StringBuilder desc = new StringBuilder("Yummy");

    public Appler(String color,int weight,int volume,Location loc) {
        this.color = color;
        this.weight = weight;
        this.volume = volume;
        this.loc = loc;
    }
    public String getClor() {
        return color;
    }

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

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public Location getLoc() {
        return loc;
    }

    public void setLoc(Location loc) {
        this.loc = loc;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Appler appler = (Appler)super.clone();
        appler.loc = (Location) loc.clone();
        appler.desc = new StringBuilder(this.desc);
        return appler;
    }

    @Override
    public String toString() {
        return "Appler{" +
                "color='" + color + '\'' +
                ", weight=" + weight +
                ", volume=" + volume +
                ", loc=" + loc +
                ", desc=" + desc +
                '}';
    }
}

package com.srr.dp.clone;

public class Location implements Cloneable{
    String name;
    public Location(String name){
        this.name = name;
    }

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

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

package com.srr.dp.clone;

/**
 * Test Code
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("Luochuan"));
        Appler appler1 = (Appler) appler.clone();
        appler.getDesc().append("Excellent");
        appler.getLoc().name = "Baoji";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

Run result:

 

If so, you will find that the apper1 value does not change when the appler's desc value changes.

The prototype pattern is described here.

The original is not easy, please support it!

Topics: Java Attribute