1. 程式人生 > >JAVA設計模式之原型模式(prototype)

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

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

原創不易,請多多支