創建型模式:原型

原型(Prototype)模式也是解決對象創建常見場景的一種手段,理解起來非常簡單,其核心是clone方法,可以圍繞着拷貝(淺拷貝+深拷貝)以及序列化等場景進行考慮和展開。

模式場景與說明

類的初始化消耗硬件或者其他資源過多,或者對象準備非常繁瑣但是同時有大量重複性的設定等場景,簡單來說當我們創建一個對象的時候希望使用copy命令來完成的時候(當然不同語言中的實現是不同的,此處說的是期待的特性),這個時候就是原型模式起作用的時候了。

實現方式

在Java中,由於已經提供了Cloneable接口,實現起來更加簡單,Java的原型模式和語言本身已經結合的比較緊密,Java的Cloneable接口是java.lang包下的一個接口,如果確認其內容,會看到如下信息

public interface Cloneable {
}

實現示例

在這裏插入圖片描述

示例代碼:淺拷貝

class Graphics {
    private String brand;
    private String volume;

    public Graphics(String brand, String volume) {
        this.brand = brand;
        this.volume = volume;

        System.out.println("Graphics: construct function called.");
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

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

    public String getBrand() {
        return brand;
    }

    public String getVolume() {
        return volume;
    }

    @Override
    public String toString(){
        return this.brand + " " + this.volume;
    }
}

class Computer implements Cloneable {
    private String cpu;
    private String memory;
    private Graphics graphics;
    private String motherboard;

    public Computer(String cpu, String memory, Graphics graphics, String motherboard) {
        this.cpu = cpu;
        this.memory = memory;
        this.graphics = graphics;
        this.motherboard = motherboard;

        System.out.println("Computer: construct function called.");
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public void setGraphics(Graphics graphics) {
        this.graphics = graphics;
    }

    public void setMotherboard(String motherboard) {
        this.motherboard = motherboard;
    }

    public String getCpu() {
        return cpu;
    }

    public String getMemory() {
        return memory;
    }

    public Graphics getGraphics() {
        return graphics;
    }

    public String getMotherboard() {
        return motherboard;
    }

    @Override
    protected Object clone(){
        Computer computer = null;

        try {
            computer = (Computer) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return computer;
    }

    @Override
    public String toString(){
        return "Computer information: \n"
                + "CPU: " + this.cpu + "\n"
                + "Memory: " + this.memory + "\n"
                + "Graphics: " + this.graphics + "\n"
                + "Motherboard: " + this.motherboard;
    }
}

public class TestPrototype {
    public static void main(String[] args) {
        Computer computer1 = new Computer("2.5 GHz Quad-Core Intel Core i7", "16 GB 1600 MHz DDR3",
                new Graphics("Intel Iris Pro","1536 MB"),"820-00xxx");

        System.out.println("clone begins ...");
        Computer computer2 = (Computer) computer1.clone();
        System.out.println("clone ends ...");

        System.out.println("computer1.equals(computer2): " + computer1.equals(computer2));
        System.out.println("computer1 == computer2: " + (computer1 == computer2));
        System.out.println("computer1.getClass() == computer2.getClass(): " + (computer1.getClass() == computer2.getClass()));

        System.out.println("set memory of computer 1:");
        computer1.setMemory("32G");
        System.out.println(computer1);
        System.out.println(computer2);

        System.out.println("set Graphics of computer 2:");
        computer2.getGraphics().setVolume("3072 MB");
        System.out.println(computer1);
        System.out.println(computer2);
    }
}

執行結果

Graphics: construct function called.
Computer: construct function called.
clone begins ...
clone ends ...
computer1.equals(computer2): false
computer1 == computer2: false
computer1.getClass() == computer2.getClass(): true
set memory of computer 1:
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 32G
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
set Graphics of computer 2:
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 32G
Graphics: Intel Iris Pro 3072 MB
Motherboard: 820-00xxx
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Graphics: Intel Iris Pro 3072 MB
Motherboard: 820-00xxx

結果分析

從上述示例代碼的執行結果中可以看到,又如下特點:

  • 執行clone時並未觸發構建函數
  • 對於基本類型的修改並不影響副本的值
  • 嵌套類的拷貝上述示例僅實現引用程度的實現,修改其中之一,其副本也會收到影響,這就是所謂的淺拷貝和深拷貝

示例代碼:深拷貝

對於其引用的對象也實現Cloneable接口,並在clone實現中加入處理,將代碼修改如下:

class Graphics implements Cloneable{
    private String brand;
    private String volume;

    public Graphics(String brand, String volume) {
        this.brand = brand;
        this.volume = volume;

        System.out.println("Graphics: construct function called.");
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

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

    public String getBrand() {
        return brand;
    }

    public String getVolume() {
        return volume;
    }

    @Override
    protected Object clone(){
        Graphics graphics = null;
        try {
            graphics = (Graphics) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return graphics;
    }
    @Override
    public String toString(){
        return this.brand + " " + this.volume;
    }
}

class Computer implements Cloneable {
    private String cpu;
    private String memory;
    private Graphics graphics;
    private String motherboard;

    public Computer(String cpu, String memory, Graphics graphics, String motherboard) {
        this.cpu = cpu;
        this.memory = memory;
        this.graphics = graphics;
        this.motherboard = motherboard;

        System.out.println("Computer: construct function called.");
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public void setGraphics(Graphics graphics) {
        this.graphics = graphics;
    }

    public void setMotherboard(String motherboard) {
        this.motherboard = motherboard;
    }

    public String getCpu() {
        return cpu;
    }

    public String getMemory() {
        return memory;
    }

    public Graphics getGraphics() {
        return graphics;
    }

    public String getMotherboard() {
        return motherboard;
    }

    @Override
    protected Object clone(){
        Computer computer = null;

        try {
            computer = (Computer) super.clone();
            computer.setGraphics((Graphics) this.getGraphics().clone());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return computer;
    }

    @Override
    public String toString(){
        return "Computer information: \n"
                + "CPU: " + this.cpu + "\n"
                + "Memory: " + this.memory + "\n"
                + "Graphics: " + this.graphics + "\n"
                + "Motherboard: " + this.motherboard;
    }
}

public class TestPrototype {
    public static void main(String[] args) {
        Computer computer1 = new Computer("2.5 GHz Quad-Core Intel Core i7", "16 GB 1600 MHz DDR3",
                new Graphics("Intel Iris Pro","1536 MB"),"820-00xxx");

        System.out.println("clone begins ...");
        Computer computer2 = (Computer) computer1.clone();
        System.out.println("clone ends ...");

        System.out.println("computer1.equals(computer2): " + computer1.equals(computer2));
        System.out.println("computer1 == computer2: " + (computer1 == computer2));
        System.out.println("computer1.getClass() == computer2.getClass(): " + (computer1.getClass() == computer2.getClass()));

        System.out.println("set memory of computer 1:");
        computer1.setMemory("32G");
        System.out.println(computer1);
        System.out.println(computer2);

        System.out.println("set Graphics of computer 2:");
        computer2.getGraphics().setVolume("3072 MB");
        System.out.println(computer1);
        System.out.println(computer2);
    }
}

執行結果

Graphics: construct function called.
Computer: construct function called.
clone begins ...
clone ends ...
computer1.equals(computer2): false
computer1 == computer2: false
computer1.getClass() == computer2.getClass(): true
set memory of computer 1:
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 32G
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
set Graphics of computer 2:
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 32G
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Graphics: Intel Iris Pro 3072 MB
Motherboard: 820-00xxx

可以看到,此種方式之下已經實現了所謂深拷貝,返回的computer2中的Graphics對象並不再是一個指向相同地址的引用,修改不再相互影響。

示例代碼:序列化

除了通過Cloneable接口,通過Serializable接口也可以非常容易地實現深拷貝,將本文的示例代碼簡單修正如下:

import java.io.*;

class Graphics implements Serializable {
    private String brand;
    private String volume;

    public Graphics(String brand, String volume) {
        this.brand = brand;
        this.volume = volume;

        System.out.println("Graphics: construct function called.");
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

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

    public String getBrand() {
        return brand;
    }

    public String getVolume() {
        return volume;
    }

    @Override
    public String toString(){
        return this.brand + " " + this.volume;
    }
}

class Computer implements Serializable {
    private String cpu;
    private String memory;
    private Graphics graphics;
    private String motherboard;

    public Computer(String cpu, String memory, Graphics graphics, String motherboard) {
        this.cpu = cpu;
        this.memory = memory;
        this.graphics = graphics;
        this.motherboard = motherboard;

        System.out.println("Computer: construct function called.");
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public void setGraphics(Graphics graphics) {
        this.graphics = graphics;
    }

    public void setMotherboard(String motherboard) {
        this.motherboard = motherboard;
    }

    public String getCpu() {
        return cpu;
    }

    public String getMemory() {
        return memory;
    }

    public Graphics getGraphics() {
        return graphics;
    }

    public String getMotherboard() {
        return motherboard;
    }

    public Computer copy() throws IOException, ClassNotFoundException {
        //get current object
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(this);

        //create new object
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);

        return (Computer) ois.readObject();
    }

    @Override
    public String toString(){
        return "Computer information: \n"
                + "CPU: " + this.cpu + "\n"
                + "Memory: " + this.memory + "\n"
                + "Graphics: " + this.graphics + "\n"
                + "Motherboard: " + this.motherboard;
    }
}

public class TestPrototype {
    public static void main(String[] args) {
        Computer computer1 = new Computer("2.5 GHz Quad-Core Intel Core i7", "16 GB 1600 MHz DDR3",
                new Graphics("Intel Iris Pro","1536 MB"),"820-00xxx");

        System.out.println("clone begins ...");
        Computer computer2 = null;
        try {
            computer2 = (Computer) computer1.copy();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("clone ends ...");

        System.out.println("computer1.equals(computer2): " + computer1.equals(computer2));
        System.out.println("computer1 == computer2: " + (computer1 == computer2));
        System.out.println("computer1.getClass() == computer2.getClass(): " + (computer1.getClass() == computer2.getClass()));

        System.out.println("set memory of computer 1:");
        computer1.setMemory("32G");
        System.out.println(computer1);
        System.out.println(computer2);

        System.out.println("set Graphics of computer 2:");
        computer2.getGraphics().setVolume("3072 MB");
        System.out.println(computer1);
        System.out.println(computer2);
    }
}

執行結果

Graphics: construct function called.
Computer: construct function called.
clone begins ...
clone ends ...
computer1.equals(computer2): false
computer1 == computer2: false
computer1.getClass() == computer2.getClass(): true
set memory of computer 1:
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 32G
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
set Graphics of computer 2:
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 32G
Graphics: Intel Iris Pro 1536 MB
Motherboard: 820-00xxx
Computer information: 
CPU: 2.5 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Graphics: Intel Iris Pro 3072 MB
Motherboard: 820-00xxx

其他設計模式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章