JS設(shè)計模式深入理解—工廠模式、寄生構(gòu)造函數(shù)模式和穩(wěn)妥構(gòu)造函數(shù)模式的區(qū)別

在學(xué)習(xí)《JavaScript高級程序設(shè)計》(第3版)第六章創(chuàng)建對象時齿穗,遇到了針對創(chuàng)建自定義類型對象的幾種設(shè)計模式吠昭。其中的工廠模式寄生構(gòu)造函數(shù)模式以及穩(wěn)妥構(gòu)造函數(shù)模式三者在實現(xiàn)上十分相似喊括,但卻具有微妙的差別,所以對它們做一個總結(jié)矢棚。

一郑什、工廠模式

function createPerson(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}

var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

工廠模式顧名思義,就是通過定義一個通用的函數(shù)蒲肋,將對象的所有創(chuàng)建工作都封裝到這個函數(shù)中蘑拯。之后每當(dāng)需要創(chuàng)建一個對象時钝满,只需要調(diào)用這個函數(shù),同時給出初始化對象所需的各個參數(shù)申窘,就能自動返回創(chuàng)建好的對象弯蚜。這就如同工廠里批量生產(chǎn)一件件產(chǎn)品一般,因為創(chuàng)建出的所有對象之間雖然內(nèi)容不同剃法,但都出自同一模板碎捺。

二、寄生構(gòu)造函數(shù)模式

function Person(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

寄生構(gòu)造函數(shù)模式與工廠模式極為相似贷洲,區(qū)別在于:

  • 寄生構(gòu)造函數(shù)模式將工廠模式中的那個通用函數(shù)createPerson()改名為Person()收厨,并將其看作為對象的構(gòu)造函數(shù)。
  • 創(chuàng)建對象實例時优构,寄生構(gòu)造函數(shù)模式采用new操作符

那么兩者有什么功能上的差別呢诵叁?事實上,兩者本質(zhì)上的差別僅在于new操作符(因為函數(shù)取什么名字無關(guān)緊要)俩块,工廠模式創(chuàng)建對象時將createPerson看作是普通的函數(shù)黎休,而寄生構(gòu)造函數(shù)模式創(chuàng)建對象時將Person看作是構(gòu)造函數(shù),不過這對于創(chuàng)建出的對象來說玉凯,沒有任何差別势腮。

對于兩者的差別,作者在書中是這么說的:

除了使用new操作符并把使用的包裝函數(shù)叫做構(gòu)造函數(shù)之外漫仆,這個模式跟工廠模式其實是一模一樣的捎拯。構(gòu)造函數(shù)在不返回值的情況下,默認會返回新對象實例盲厌。而通過在構(gòu)造函數(shù)的末尾添加一個return語句署照,可以重寫調(diào)用構(gòu)造函數(shù)時返回的值。

根據(jù)作者的意思吗浩,構(gòu)造函數(shù)和普通函數(shù)的區(qū)別在于:當(dāng)使用new+構(gòu)造函數(shù)創(chuàng)建對象時建芙,如果構(gòu)造函數(shù)內(nèi)部沒有return語句,那么默認情況下構(gòu)造函數(shù)將返回一個該類型的實例(如果以上面的例子為參考懂扼,person1和person2為Person類型的對象實例禁荸,可以使用person1 instanceof Person檢驗),但如果構(gòu)造函數(shù)內(nèi)部通過return語句返回了一個其它類型的對象實例阀湿,那么這種默認的設(shè)置將被打破赶熟,構(gòu)造函數(shù)最終返回的實例類型將以return語句中對象實例的類型為準。

基于這個規(guī)則陷嘴,在Person()構(gòu)造函數(shù)中映砖,由于最后通過return語句返回了一個Object類型的對象實例,所以通過該構(gòu)造函數(shù)創(chuàng)建的對象實際上是Object類型而不是Person類型灾挨;這樣一來就與createPerson()函數(shù)返回的對象類型相同邑退,因此可以說工廠模式和寄生構(gòu)造函數(shù)模式在功能上是等價的竹宋。

如果非要說兩者的不同,并且要從其中選擇一個作為創(chuàng)建對象的方法的話地技,我個人更偏向于寄生構(gòu)造函數(shù)模式一些逝撬。這是因為new Person()(寄生構(gòu)造函數(shù)模式)更能讓我感覺到自己正在創(chuàng)建一個對象,而不是在調(diào)用一個函數(shù)(工廠模式)乓土。

三、穩(wěn)妥構(gòu)造函數(shù)模式

function Person(para_name, para_age, para_job) {
    //創(chuàng)建要返回的對象
    var o = {};

    //在這里定義私有屬性和方法
    var name = para_name;
    var age = para_age;
    var job = para_job;

    var sayAge = function() {
        alert(age);
    };

    //在這里定義公共方法
    o.sayName = function() {
        alert(name);
    };

    //返回對象
    return o;
}

var person1 = Person("Nicholas", 29, "Software Engineer");    //創(chuàng)建對象實例
person1.sayName();    //Nicholas
person1.name;         //undefined
person1.sayAge();     // 報錯

穩(wěn)妥構(gòu)造函數(shù)模式與前面介紹的兩種設(shè)計模式具有相似的地方溯警,都是在函數(shù)內(nèi)部定義好對象之后返回該對象來創(chuàng)建實例趣苏。然而穩(wěn)妥構(gòu)造函數(shù)模式的獨特之處在于具有以下特點:

  • 沒有通過對象定義公共屬性
  • 在公共方法中不使用this引用對象自身
  • 不使用new操作符調(diào)用構(gòu)造函數(shù)

這種設(shè)計模式最適合在一些安全的環(huán)境中使用(這些環(huán)境中會禁止使用this和new);為了較好地理解這種設(shè)計模式梯轻,我們可以采取類比的方法——這種構(gòu)造對象的方式就如同C++/Java語言中通過訪問控制符private定義出包含私有成員的類的方式一樣(將上例按C++中類的方式來定義):

class Person {
//定義私有成員變量和函數(shù)
private: 
    string name;
    int age;
    string job;
    int sayAge() {return age;}
//定義構(gòu)造函數(shù)和公共方法(函數(shù))
public:
    string sayName() {return name;}    //公共方法
    Person(string p_name, int p_age, string p_job):name(p_name),age(p_age),job(p_job) {}  //構(gòu)造函數(shù)
}

//創(chuàng)建對象實例
Person person1("Nicholas", 29, "Software Engineer");
person1.sayName();    //Nicholas
person1.name;         //報錯(無法訪問)
person1.sayAge();     //報錯(無法訪問)

可見食磕,利用C++定義出了一個Person類,其中的name喳挑、age彬伦、job以及sayAge()是私有成員,無法通過類似person1.name的方式直接訪問伊诵,這是一種類的保護機制单绑;而定義為publicsayName()函數(shù)則可以直接訪問。

JS中的穩(wěn)妥構(gòu)造函數(shù)模式正是為了實現(xiàn)這樣的數(shù)據(jù)保護機制曹宴。它巧妙地利用了函數(shù)的作用域?qū)崿F(xiàn)了對象屬性的私有化:在函數(shù)中定義的變量是局部變量搂橙,按道理本應(yīng)該在函數(shù)執(zhí)行完畢退出后進行銷毀或清理,但由于通過對象的公共方法對該局部變量保持著引用笛坦,所以該變量即便是在構(gòu)造函數(shù)退出之后也依然保持有效(閉包)区转。

這樣一來,創(chuàng)建出的對象既能通過公共方法提供的訪問接口對私有屬性進行訪問(引用的是構(gòu)造函數(shù)的局部變量)版扩,也能保證無法通過對象自身對其直接訪問(person1.name無法訪問到對應(yīng)數(shù)據(jù)废离,因為name是構(gòu)造函數(shù)的局部變量而不是對象的屬性),從而保證了對象屬性的訪問安全礁芦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜻韭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宴偿,更是在濱河造成了極大的恐慌湘捎,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窄刘,死亡現(xiàn)場離奇詭異窥妇,居然都是意外死亡,警方通過查閱死者的電腦和手機娩践,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門活翩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烹骨,“玉大人,你說我怎么就攤上這事材泄【诨溃” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵拉宗,是天一觀的道長峦树。 經(jīng)常有香客問我,道長旦事,這世上最難降的妖魔是什么魁巩? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮姐浮,結(jié)果婚禮上谷遂,老公的妹妹穿的比我還像新娘。我一直安慰自己卖鲤,他們只是感情好肾扰,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛋逾,像睡著了一般集晚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上换怖,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天甩恼,我揣著相機與錄音,去河邊找鬼沉颂。 笑死条摸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铸屉。 我是一名探鬼主播钉蒲,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼彻坛!你這毒婦竟也來了顷啼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤昌屉,失蹤者是張志新(化名)和其女友劉穎钙蒙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體间驮,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡躬厌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了竞帽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扛施。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸿捧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疙渣,到底是詐尸還是另有隱情匙奴,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布妄荔,位于F島的核電站泼菌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏啦租。R本人自食惡果不足惜灶轰,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刷钢。 院中可真熱鬧,春花似錦乳附、人聲如沸内地。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阱缓。三九已至,卻和暖如春举农,著一層夾襖步出監(jiān)牢的瞬間荆针,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工颁糟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留航背,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓棱貌,卻偏偏與公主長得像玖媚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子婚脱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容