spring中的原型模式


大家好,我原本是神劍山庄的鑄劍師,名叫小趙,本來干的好好的,后來一時興起,睡了三少爺的小姨子,與其一直提心吊膽,干脆來個逃之夭夭。

 但是,我也要吃飯的呀,工作也得找,神劍山庄去不得,還有斷劍山庄、藏劍山庄、盪劍山庄、等等等等大型企業,說不定這次跳槽,能跳出個飛黃騰達!

為了提高我投簡歷的准確性,我覺得簡歷要寫的多樣化,不能全寫一模一樣,比如說我的期望薪資不能寫成一樣,因為我希望能夠根據目標企業的情況來投遞合適薪資的簡歷,這樣中標概率大一點。

 這是我的簡歷類:

復制代碼
public class Resume {
    private String name;
    private String position;
    private int salary;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Resume{" +
                "name='" + name + '\'' +
                ", position='" + position + '\'' +
                ", salary=" + salary +
                '}';
    }
}
復制代碼

 

  現在,我正在熬夜寫簡歷。。。。。

復制代碼
    public static void main(String[] args) {
        Resume resume1 = new Resume();
        resume1.setName("小趙");
        resume1.setPosition("高級鑄劍工程師");
        resume1.setSalary(1000);

        Resume resume2 = new Resume();
        resume2.setName("小趙");
        resume2.setPosition("高級鑄劍工程師");
        resume2.setSalary(1200);

        Resume resume3 = new Resume();
        resume2.setName("小趙");
        resume3.setPosition("高級鑄劍工程師");
        resume3.setSalary(1500);
        //.....
    }
復制代碼

  當我寫到20多份的時候,我已經睡着了。。。。。

  唉,找工作難啊。。。。。。

 

打印機跑起來

  第二天,我去萬達廣場買了個打印機回來,直接循環打印!

復制代碼
    public static void main(String[] args) {
        int num = 5;
        while (num > 0){
            Resume resume1 = new Resume();
            int salary = (int)(1000+Math.random()*(2000-1000+1));
            resume1.setName("小趙");
            resume1.setPosition("高級鑄劍工程師");
            resume1.setSalary(salary);
            System.out.println(resume1.toString());
            num --;
        }
    }
復制代碼

輸出:

Resume{name='小趙', position='高級鑄劍工程師', salary=1389}
Resume{name='小趙', position='高級鑄劍工程師', salary=1383}
Resume{name='小趙', position='高級鑄劍工程師', salary=1345}
Resume{name='小趙', position='高級鑄劍工程師', salary=1446}
Resume{name='小趙', position='高級鑄劍工程師', salary=1221}

 

  先試了一下,打印5份簡歷,感覺沒問題。

  有了這個打印機之后,我也接些私活,幫別人打印簡歷,生意越做越火,一個月后,我工作沒找到,但打印機一天到晚倒是沒停過。

  到了現在,我的打印機一天到晚要打印一百萬張簡歷,每次打印都要耗電耗內存耗機器壽命,我的打印機已經報廢了好幾台,並且在不斷的購買新的打印機。

  作為一個工程師,我決定要研究一下有沒有更好的解決辦法。

 

復印機跑起來

  聽說Cloneable接口有個復印機可以用,我決定去試試,效果的好的話就把復印機裝到打印機里面去,搞個多功能一體機。

  這是修改后的簡歷類:

復制代碼
public class Resume implements Cloneable{
    private String name;
    private String position;
    private int salary;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    protected Resume clone(){
        Resume resume = null;
        try{
            resume = (Resume) super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return resume;
    }

    @Override
    public String toString() {
        return "Resume{" +
                "name='" + name + '\'' +
                ", position='" + position + '\'' +
                ", salary=" + salary +
                '}';
    }
}
復制代碼

 

復印機跑起來:

復制代碼
    public static void main(String[] args) {
        int num = 5;
        Resume resume = new Resume();
        while (num > 0){
            Resume resume1 = resume.clone();
            int salary = (int)(1000+Math.random()*(2000-1000+1));
            resume1.setName("小趙");
            resume1.setPosition("高級鑄劍工程師");
            resume1.setSalary(salary);
            System.out.println(resume1.toString());
            num --;
        }
    }
復制代碼

和打印機的效果是一樣的,但是這里事實上只打印了一次,然后其他的都是拷貝復印出來的。

  。。。。。。

  多年之后,我才恍然大悟,當初我用復印機復印簡歷的做法,其實就是設計模式中的原型模式。

原型模式的使用場景

  大體上有兩種使用場景

  1.在需要一個類的大量對象的時候,使用原型模式是最佳選擇,因為原型模式是在內存中對這個對象進行拷貝,要比直接new這個對象性能要好很多,在這種情況下,需要的對象越多,原型模式體現出的優點越明顯。

  2.如果一個對象的初始化需要很多其他對象的數據准備或其他資源的繁瑣計算,那么可以使用原型模式。

  3.當需要一個對象的大量公共信息,少量字段進行個性化設置的時候,也可以使用原型模式拷貝出現有對象的副本進行加工處理。

 

構造函數的問題

  寫個程序測一下構造函數:

復制代碼
public class AAA implements Cloneable {
    public AAA() {
        System.out.println("我來了。。");
    }

    @Override
    protected AAA clone(){
        AAA aaa = null;
        try {
            aaa = (AAA) super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return aaa;
    }
}
復制代碼
    public static void main(String[] args) {
        AAA aaa = new AAA();
        AAA aaa1 = aaa.clone();
    }

輸出:

我來了。。

  就輸出一次,這里可以證明對象拷貝的時候構造函數是不會執行的,原因在於拷貝是直接在堆中進行,這其實也可以理解,new的時候,JVM要走一趟類加載流程,這個流程非常麻煩,在類加載流程中會調用構造函數,最后生成的對象會放到堆中,而拷貝就是直接拷貝堆中的現成的二進制對象,然后重新一個分配內存塊。

 

淺拷貝

  上個例子展示什么是淺拷貝

  這里新加一個類BBB:

復制代碼
public class BBB{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
復制代碼

 

  AAA類修改為:

復制代碼
public class AAA implements Cloneable {
    private BBB bbb = new BBB();

    public void setName(String name) {
        this.bbb.setName(name);
    }

    public String getName() {
        return this.bbb.getName();
    }

    @Override
    protected AAA clone(){
        AAA aaa = null;
        try {
            aaa = (AAA) super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return aaa;
    }
}
復制代碼

 

  main方法:

復制代碼
    public static void main(String[] args) {
        AAA aaa = new AAA();
        aaa.setName("張三");
        System.out.println(aaa.getName());

        AAA aaa1 = aaa.clone();
        System.out.println(aaa1.getName());
    }
復制代碼

輸出:

張三
張三

  這種情況就是淺拷貝,java只拷貝你指定的對象,至於你指定的對象里面的別的對象,它不拷貝,還是把引用給你,共享變量,這是一種非常不安全的方式,需要特別注意。

  內部的數組和引用對象不會拷貝,其他的原始基本類型和String類型會被拷貝。

 

  如果要實現深拷貝呢?

  那就只能在AAA的clone方法里把BBB實例化出來了:

復制代碼
    @Override
    protected AAA clone(){
        AAA aaa = null;
        try {
            aaa = (AAA) super.clone();
            aaa.bbb = new BBB();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return aaa;
    }
復制代碼

 原文引用:https://www.cnblogs.com/fengyumeng/p/10646487.html


免責聲明!

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



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