設(shè)計(jì)模式大總結(jié)(四):原型模式

前言#

今天是周五了,在美好的周末到來之前趕緊寫點(diǎn)東西來證明自己這周沒有當(dāng)一條咸魚。

原型模式:用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這些原型來創(chuàng)建新的對(duì)象。

這句話看著高大上,實(shí)際上是我從網(wǎng)上拷貝過來的,原型模式跟我們之前的寫過的幾種模式,例如觀察者,代理模式等等,是不一樣的,與其說他是一種模式,不如說是一種優(yōu)化,因?yàn)樗]有改變?cè)瓉淼拇a邏輯結(jié)構(gòu),僅僅是在創(chuàng)建對(duì)象上,進(jìn)行了優(yōu)化。

正文#

Object本身就有clone方法,這個(gè)方法是protect修飾符,所以我們需要把clone方法暴露出來,看一下Student的代碼示例:

public class Student implements Cloneable {

    private String name = "xxx";

    private String sex = "man";

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return new Student();
        }
    }

    @Override
    public String toString() {
        return "my name is " + getName() + ":" + hashCode();
    }
}

要想把clone方法暴露出來,需要一下兩個(gè)步驟:

1、實(shí)現(xiàn)Cloneable接口,雖然這個(gè)接口里并沒有方法。
2、創(chuàng)建一個(gè)public方法,調(diào)用clone方法,并實(shí)現(xiàn)自己的邏輯。

ok,運(yùn)行一下,看看有沒有效果:

Student student = new Student();
// 修改一下默認(rèn)的student名字,為了證明調(diào)用的是clone方法,而不是new
student.setName("lisi");
Student student1 = (Student) student.clone();

System.out.println(student.toString());
System.out.println(student1.toString());
這里寫圖片描述

從上面的運(yùn)行結(jié)果上看,通過clone方法創(chuàng)建并返回了一個(gè)新的Student對(duì)象。

那么new創(chuàng)建對(duì)象和clone創(chuàng)建對(duì)象的運(yùn)行效率如何呢?我們分別創(chuàng)建10000個(gè),對(duì)比一下耗時(shí)的時(shí)間:

這里寫圖片描述

從結(jié)果上看,創(chuàng)建10000個(gè)對(duì)象,clone的耗時(shí)要比new多耗費(fèi)了5毫秒,雖然速度稍慢,但是效率還是不錯(cuò)的。
(別著急,關(guān)于這個(gè)效率的問題,后面還有更具體的驗(yàn)證)

既然new關(guān)鍵字的效率比clone要高,我們還要clone有個(gè)卵用??

原型模式的使用場景

為什么要使用原型模式呢?首先我們要回到我們學(xué)習(xí)設(shè)計(jì)模式的起點(diǎn):

設(shè)計(jì)模式更多的是為了提高代碼可維護(hù)性,擴(kuò)展性,可讀性,對(duì)各個(gè)模塊之間進(jìn)行解耦,利于開發(fā)和維護(hù)。

有些時(shí)候我們不得不犧牲掉在可以接受的范圍內(nèi)的運(yùn)行效率,來完成目標(biāo)模式。

魚和熊掌不可得兼,所以我們要權(quán)衡犧牲的代價(jià)和得到的收益,過分追求效率,可能會(huì)讓我們迷失了真正的目標(biāo)。

說了這么多,原型模式適合什么樣的場景呢:

某一個(gè)類(Class),可以大量復(fù)用已有的對(duì)象的屬性,適合原型模式。

也就是說,我們需要的類的新對(duì)象和已有的對(duì)象的相比,幾乎不需要修改就可以直接用,而且屬性越多,原型模式體現(xiàn)的優(yōu)勢(shì)越好,光說不練沒有用,下面就舉個(gè)例子:

某市進(jìn)行高效運(yùn)動(dòng)會(huì),我們需要統(tǒng)計(jì)各個(gè)學(xué)校參加的學(xué)生,學(xué)生資料中,包含了學(xué)校的信息。

先定義學(xué)校School對(duì)象:

/**
 * Created by li.zhipeng on 2017/9/15.
 * <p>
 * 自定義學(xué)生類
 */

public class Student implements Cloneable {

    // 以下全是學(xué)校資料
    private String area; // 所在的區(qū)
    private String address; // 地址
    private String slogan; // 學(xué)校的宣傳語
    private int level; // 學(xué)校的級(jí)別
    private int teacherNum; // 老師的數(shù)量
    private int studentNum; // 學(xué)生的數(shù)量
    ... // 還有很多信息

    // 以下全是學(xué)生資料
    private String name = "xxx";
    private String sex = "boy";
}

我們看到在Student中,如果是同一個(gè)學(xué)校的學(xué)生,我們只要修改其中的name和sex就可以了,我有兩種方法通過學(xué)生a,得到同一個(gè)學(xué)校的同學(xué)b的信息:

// 通過new
Student b  = new Student();
b.setArea(a.getArea());
b.setAddress(a.getAddress());
b.setSlogan(a.getSlogan());
b.setLevel(a.getLevel());
b.setTeacherNum(a.getTeacherNum());
b.setStudentNum(a.getStudentNum());
b.setName("zhangsan");
b.setSex("boy");

// 通過clone
Student c = (Student) a.clone();
c.setName("wangwu");
c.setSex("boy");

是不是對(duì)比非常明顯,相信這個(gè)時(shí)候你已經(jīng)看到了原型模式的代碼是多么的簡潔。

為clone的效率討一個(gè)說法

我們剛才驗(yàn)證了,如果不重寫構(gòu)造方法,屬性很少的情況下,new確實(shí)比clone的效率要高,但是如果需要重寫構(gòu)造方法,或者是屬性很多呢?

1、通過new關(guān)鍵字,創(chuàng)建屬性很多的對(duì)象,取3組數(shù)據(jù):

long time = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
      Student student = new Student();
}
// 打印時(shí)間...

time = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
     Student student1 = (Student) original.clone();
}
// 打印時(shí)間...
這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

經(jīng)過對(duì)比,如果是創(chuàng)建對(duì)象屬性很多的對(duì)象,new比clone確實(shí)要快一些。

2、對(duì)比new創(chuàng)建了之后,還要通過setter方法改變屬性,去3組數(shù)據(jù):

long time = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
    Student b = new Student();
    b.setArea(original.getArea());
    b.setAddress(original.getAddress());
    b.setSlogan(original.getSlogan());
    b.setLevel(original.getLevel());
    b.setTeacherNum(original.getTeacherNum());
    b.setStudentNum(original.getStudentNum());
    b.setName("zhangsan");
    b.setSex("boy");
}
// 打印時(shí)間...

time = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
     Student c = (Student) original.clone();
     c.setName("wangwu");
     c.setSex("boy");
}
// 打印時(shí)間...
這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

由結(jié)果我們可以看出,setter方法是比較耗時(shí)的,通過原型模式,我們盡可能的避免setter,所以在運(yùn)行時(shí)間上已經(jīng)顯示出優(yōu)勢(shì)。

3、重寫Student默認(rèn)的構(gòu)造方法,取3組數(shù)據(jù):

public Student(){
        System.out.println("Create Student Object...");
}

// 測試代碼與第2中情況相同
這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

是不是覺得十分意外,從結(jié)果上我們發(fā)現(xiàn)了clone是會(huì)調(diào)用類的構(gòu)造方法的,僅僅是對(duì)對(duì)象的克隆,所以在運(yùn)行時(shí)間上的優(yōu)勢(shì)大幅提升。

總結(jié)#

回顧一下今天的內(nèi)容:

1、首先我們了解了原型模式的定義,以及clone方法的使用步驟。

2、了解了原型模式的使用場景,實(shí)際體會(huì)原型模式在代碼上為我們帶來的簡潔體驗(yàn)。

3、根據(jù)不同情況,對(duì)比new和clone創(chuàng)建對(duì)象的效率,clone的運(yùn)行效率在大部分應(yīng)用場景會(huì)讓創(chuàng)建對(duì)象的速度更快,效率更高。

ok,今天所有的內(nèi)容就結(jié)束了,祝大家周末愉快~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • 1大同小異的工作周報(bào) Sunny軟件公司一直使用自行開發(fā)的一套OA (Office Automatic,辦公自動(dòng)化...
    justCode_閱讀 1,242評(píng)論 0 3
  • 1 場景問題# 1.1 訂單處理系統(tǒng)## 考慮這樣一個(gè)實(shí)際應(yīng)用:訂單處理系統(tǒng)。 現(xiàn)在有一個(gè)訂單處理的系統(tǒng),里面有個(gè)...
    七寸知架構(gòu)閱讀 4,666評(píng)論 3 63
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,728評(píng)論 18 399
  • 碰到這個(gè)需求,需要在應(yīng)用里面添加一個(gè)懸浮的按鈕,一直處在屏幕的最上面,并且在特定的界面不顯示,類似與蘋果手機(jī)上的那...
    xiao小馬哥閱讀 613評(píng)論 0 3

友情鏈接更多精彩內(nèi)容