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的值並沒有發生改變。

寫到這里原型模式就介紹完了。

原創不易,請多多支持!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM