JAVA设计模式之原型模式(prototype)

原型模式:

  • 原型模式又叫克隆模式
  • Java自带克隆模式
  • 实现克隆模式必须实现Cloneable
  • 接口,如果不实现会发生java.lang.CloneNotSupportedException异常
  • 当某个类的属性已经设定好需要创建很多相同属性值的对象的时候使用clone模式非常方便
  • 使用clone模式不见得比传统的new方式性能高
  • 浅克隆和深克隆

先看下面的代码,没有实现Cloneable接口

package com.srr.dp.clone;

/**
 * (原型模式)克隆模式
 */
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);
    }
}

运行结果:

 

浅拷贝:

package com.srr.dp.clone;

/**
 * (原型模式)克隆模式
 *  浅拷贝
 */
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;

/**
 * 测试代码
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("洛川"));
        Appler appler1 = (Appler) appler.clone();
        appler.setClor("red");
        appler.getLoc().name = "宝鸡";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

运行结果:

 

从结果发现,当改变appler 的颜色还有location的值后,拷贝的apper1对象的颜色未发生改变但是location发生了改变。

这就是浅拷贝,引用对象无法保证拷贝之后完全独立只是拷贝了地址但是地址指向的对象是共享的,

虽然String类型也是引用类型但是共享常量池所以不会有这个问题。

那么如何让引用类型拷贝之后独立呢?

那么就要使用深拷贝请看如下代码:

package com.srr.dp.clone;

/**
 * (原型模式)克隆模式
 *  浅拷贝
 */
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;

/**
 * 测试代码
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("洛川"));
        Appler appler1 = (Appler) appler.clone();
        appler.setClor("red");
        appler.getLoc().name = "宝鸡";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

运行结果:

从结果发现,当改变appler 的颜色还有location的值后,拷贝的apper1对象的颜色未发生改变location也发生了改变。

 上面说到String类型的拷贝不存在浅拷贝的问题,那么StringBuilder或者StringBuffer呢,鉴于篇幅这里使用StringBuilder来举例

请看代码:

package com.srr.dp.clone;

/**
 * (原型模式)克隆模式
 *  浅拷贝
 */
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("好吃");

    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;

/**
 * 测试代码
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("洛川"));
        Appler appler1 = (Appler) appler.clone();
        appler.getDesc().append("得不得了");
        appler.getLoc().name = "宝鸡";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

运行结果:

 

 这是是后你会发现当appler的desc值发生改变之后,apper1的值也发生改变了,说明StringBuilder的拷贝方式为浅拷贝,那么如何实现深拷贝呢

请看代码:

package com.srr.dp.clone;

/**
 * (原型模式)克隆模式
 *  浅拷贝
 */
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("好吃");

    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;

/**
 * 测试代码
 */
public class T {
    public static void main(String[] args) throws CloneNotSupportedException {
        Appler appler = new Appler("yellow",1,1,new Location("洛川"));
        Appler appler1 = (Appler) appler.clone();
        appler.getDesc().append("得不得了");
        appler.getLoc().name = "宝鸡";
        System.out.println("appler1 = "+appler1);
        System.out.println("appler = "+appler);
    }
}

运行结果:

 

这是是后你会发现当appler的desc值发生改变之后,apper1的值并没有发生改变。

写到这里原型模式就介绍完了。

原创不易,请多多支持!