天天看點

深入了解JavaScript的設計模式

深入了解JavaScript的設計模式

使用适當的設計模式可以幫助你編寫更好、更易于了解的代碼。這樣的代碼也更容易維護。但是,重要的是不要過度使用它們。在使用設計模式之前,你應該仔細考慮你的問題是否符合設計模式。

當你開始一個新的項目時,你不會立即開始編碼。你必須定義項目的目的和範圍,然後列出項目特性或規格說明。之後,你可以開始編寫代碼,或者,如果你正在參與的是一個更複雜的項目,那麼你應該選擇一個最适合項目的設計模式。

什麼是設計模式?

在軟體工程中,設計模式是軟體設計中常見問題的可重用解決方案。設計模式代表了經驗豐富的軟體開發人員所使用的最佳實踐。設計模式可以看作是程式設計模闆。

為什麼要使用設計模式?

有許多程式員,他們要麼認為設計模式浪費時間,要麼不知道如何恰當地應用它們。但是,使用适當的設計模式可以幫助你編寫更好、更易于了解的代碼。這樣的代碼也更容易維護。

最重要的是,設計模式為軟體開發人員提供了一個可以談論的通用詞彙表。它們可以讓學習代碼的人快速了解代碼的意圖。

例如,如果你在項目中使用了裝飾模式,那麼新程式員就會立即知道那段代碼在做什麼,他們可以把更多的精力放在解決業務問題上,而不是試圖了解那段代碼在做什麼。

現在我們知道了什麼是設計模式,以及為什麼它們很重要。接下來,讓我們深入探讨下應用于 javascript 的各種設計模式。

子產品模式

子產品是一段自包含的代碼,是以,我們可以在不影響代碼其他部分的情況下更新子產品。子產品還允許我們通過為變量建立單獨的作用域來避免命名空間污染。當子產品與其他代碼片段松耦合時,我們還可以在其他項目中重用它們。

子產品是任何現代化 javascript 應用程式的組成部分,有助于保持代碼的整潔、隔離和條理性。使用 javascript 建立子產品有很多方法,其中之一就是子產品模式。

像 bit 這樣的平台可以幫助你将子產品群組件轉換成共享的建構塊,可以在任何項目中共享、發現和開發。不需要任何重構,就可以使用一種快速且可擴充的方式共享和重用代碼。

與其他程式設計語言不同,javascript 沒有通路修飾符,也就是說,不能将變量聲明為 private 或 public。是以,子產品模式也被用來模拟封裝的概念。

該模式使用 iife(即時調用函數表達式)、閉包和函數作用域來模拟這個概念,例如:

由于是 iife,是以代碼會立即執行,傳回的對象賦給 mymodule 變量。由于是閉包,是以傳回的對象仍然可以通路在 iife 中定義的函數和變量,即使在 iife 結束之後。

是以,在 iife 中定義的變量和函數本質上是對外部作用域隐藏的,這使得它成為 mymodule 變量私有的。

執行代碼後,mymodule 變量如下:

是以,我們可以調用 publicmethod(),而它又會調用 privatemethod(),例如:

揭示子產品模式

揭示子產品模式是經 christian heilmann 略微改進的子產品模式。子產品模式的問題是,我們必須建立新的公共函數來調用私有函數和變量。

在這個模式中,我們将把傳回對象的屬性映射到我們想要公開的私有函數。這就是為什麼它被稱為揭示子產品模式,例如:

這種模式使我們更容易了解哪些函數和變量可以公開通路,這有助于提高代碼的可讀性。

執行代碼之後,myrevealingmodule 是下面這個樣子:

我們可以調用 myrevealingmodule. setname ('mark'),它是對方法 publicsetname 的引用,而 myrevealingmodule.getname() 是對内部方法 publicgetname 的引用,例如:

與子產品模式相比,揭示子產品模式的優點如下

通過修改 return 語句中的一行代碼,我們就可以将成員從 public 更改為 private,反之亦然。

傳回的對象不包含任何函數定義,所有右側表達式都在 iife 中定義,這使得代碼清晰且易于閱讀。

es6 子產品

在 es6 之前,javascript 沒有内置子產品,是以,開發人員不得不依賴第三方庫或子產品模式來實作子產品。但是在 es6 中,javascript 有了本地子產品。

es6 子產品存儲在檔案中。每個檔案隻能有一個子產品。預設情況下,子產品中的所有内容都是私有的。函數、變量和類都是使用 export 關鍵字公開的。子產品内的代碼總是在嚴格模式下運作。

輸出子產品

有多種方法可以公開函數和變量聲明:

在函數和變量聲明前添加 export 關鍵字,例如:

在代碼末尾添加 export 關鍵字,其中包含我們希望公開的函數名和變量名,例如:

導入子產品

和輸出子產品類似,借助 import,有多種方法可以導入子產品:

一次導入多個項:

導入所有子產品:

導入和輸出的别名

如果你想要避免命名沖突,則可以在輸出和導入時更改名稱,例如:

重命名輸出:

重命名導入:

單例模式

單例對象是隻能執行個體化一次的對象。如果一個類的執行個體不存在,單例模式就會建立一個新的類執行個體。如果執行個體存在,它隻傳回對該對象的引用。對構造函數的任何重複調用都會擷取相同的對象。

javascript 語言一直都内置了的單例,隻是我們不把它們叫做單例,我們稱它們為對象字面量,例如:

因為 javascript 中的每個對象都占用一個唯一的記憶體位置,當我們調用 user 對象時,我們本質上是傳回了該對象的引用。

如果我們試圖将 user 變量複制到另一個變量中并修改該變量,例如:

我們會看到,兩個對象都被修改了,因為在 javascript 中,對象是通過引用傳遞的,而不是值。是以,記憶體中隻有一個對象,例如:

單例模式可以使用構造函數實作,例如:

當調用這個構造函數時,它會檢查執行個體對象是否存在。如果對象不存在,它就将這個變量賦給執行個體變量。如果對象存在,它隻傳回那個對象。

單例也可以使用子產品模式實作,例如:

在上面的代碼中,我們通過調用 singleton.getinstance 方法來建立一個新執行個體。如果執行個體已經存在,則該方法隻是傳回這個執行個體,如果執行個體不存在,則調用 init() 函數建立一個新的執行個體。

工廠模式

工廠模式使用工廠方法建立對象,而不指定所建立對象的确切類或構造函數。

工廠模式用于建立對象,而不公開執行個體化邏輯。當我們需要根據特定條件生成不同的對象時,可以使用此模式,例如:

這裡,我建立了一個 car 類和一個 truck 類(帶有一些預設值),用于建立新的 car 和 truck 對象。我還定義了一個 vehiclefactory 類,基于 options 對象中接收到的 vehicletype 屬性建立和傳回一個新的對象。

我已經建立了一個新的 vehiclefactory 類的對象工廠。之後,我們可以調用 factory.createvehicle 方法,傳入一個 vehicletype 屬性值為 car 或 truck 的 options 對象。

裝飾模式

裝飾模式用于擴充對象的功能,而不修改現有的類或構造函數。該模式可用于向對象添加特性,而不修改使用它們的底層代碼。

下面是這個模式的一個簡單例子:

對于這種模式,一個更實際的例子是,比方說,一輛車的價格取決于它有多少功能。如果沒有裝飾模式,我們将不得不為不同的特性組合建立不同的類,每個類都有計算成本的 cost 方法,例如:

但是使用裝飾模式,我們可以建立一個基類 car,并使用裝飾函數将不同配置的成本添加到它的對象中,例如:

首先,我們建立一個建立 car 對象的基類 car。然後,為要添加的功能建立裝飾,并将 car 對象作為參數傳遞。然後,我們重寫這個對象的 cost 函數,該函數傳回更新後的汽車成本,并向該對象添加一個新屬性,表明添加了哪些功能。

要添加新功能,我們可以這樣做:

最後,我們可以像下面這樣計算汽車的成本:

小結

我們已經了解了 javascript 中使用的各種設計模式,但還有一些可以用 javascript 實作的設計模式我在這裡沒有涉及。

雖然了解各種設計模式很重要,但同樣重要的是不要過度使用它們。在使用設計模式之前,你應該仔細考慮你的問題是否符合設計模式。要知道一個模式是否适合你的問題,你應該研究設計模式以及該設計模式的應用。

繼續閱讀