[譯] 現代 JavaScript 開發中的設計模式

HydeSong發表於2019-05-11

關於軟體專案設計中有效溝通的思考

[譯] 現代 JavaScript 開發中的設計模式

模式?設計?我們是在討論軟體開發麼?

當然是啦。

就像物件導向程式設計一樣,我們開發人員正試圖為我們周圍的世界建模。因此,嘗試並使用我們周圍的世界作為工具來描述我們的作品同樣有意義。

在本例中,我們效仿建築架構(有建築和橋樑的)來舉例。正如具有開創性的建築架構書籍 《建築模型語言》Christopher Alexander,Sara Ishikawa,Murray Silverstein 著)中對“模式”所描述的那樣:

每個模式都描述了我們環境中反覆出現的問題,然後描述了該問題解決方案的核心,以這樣的方式,你可以多次使用此解決方案,而不必以相同的方式重複使用兩次。

在軟體開發中,架構是以健康、健壯和可維護的方式構建應用程式的過程,模式提供了一種給常見問題解決方案命名的方法。這些解決方案可以是抽象的/概念性的,也可以是非常精確的和技術性的,並且允許開發人員有效地相互溝通。

高效

如果團隊中有兩個或更多的開發人員瞭解模式,那麼討論問題的解決方案就會變得非常高效。如果只有一個開發人員知道模式,那麼向團隊的其他成員解釋它們通常也很容易。

本文的目標是通過向你介紹軟體設計模式的概念,並介紹一些有趣的模式,以激發你對某種形式的軟體開發知識的興趣,因為它們在現代 JavaScript 專案中得到了廣泛的應用。

單例模式

概念

單例模式並不是最廣泛使用的模式之一,但是我們從它開始是因為它相對容易掌握。

單例模式源於單例的數學概念,即:

在數學中,單例,也稱為單元集合,是一個只有一個元素的集合。例如,集合 {null} 是一個單例。

在軟體中,它只是意味著我們將類的例項化限制為一個物件。第一次實現單例模式的類的物件應該被例項化,實際上它也將被例項化。任何後續嘗試都會返回第一個例項。

蝙蝠俠來了,誰還需要兩個超級英雄?

為什麼

除了我們只能有一個超級英雄(顯然是蝙蝠俠)的原因外,我們為什麼要使用單例模式呢?

儘管單例模式並非沒有問題(它以前被認為是有害的,因為單例模式 被稱為病態說謊者),但它仍然有它的用途。最值得注意的是例項化配置物件。你可能只想要應用程式的一個配置例項,除非應用程式的一個特性提供了多個配置。

用在哪裡

Angular 的服務是大型流行框架中使用單例模式的一個主要例子。在 Angular 的文件中有一個 專用頁面 解釋瞭如何確保服務總是作為單例提供。

服務是單例的非常有意義,因為服務被用作儲存狀態、配置和允許元件之間通訊的地方,你希望確保不會有多個例項混淆這些概念。

例如,假設你有一個簡單的應用程式,它用於計算按鈕被單擊的次數。

[譯] 現代 JavaScript 開發中的設計模式

你應跟蹤在一個物件內按下的按鈕次數,該物件提供:

  • 計數功能
  • 並提供當前的單擊次數。

如果該物件不是單例物件(按鈕將各自獲得自己的例項),那麼單擊計數就不正確。此外,你將向顯示當前計數的元件提供哪些計數例項?

觀察者模式

概念

觀察者模式定義如下:

觀察者模式是一種軟體設計模式,其中一個物件(稱為主題)維護它的依賴項列表(稱為觀察者),並自動通知它們任何狀態更改,通常通過呼叫它們的方法之一。

如果我們試著將觀察者模式與現實世界中的一個例子 —— 報紙訂閱 —— 進行比較,就會非常容易理解觀察者模式。

當你買報紙的時候,通常的情況是你走到報攤,問你最喜歡的報紙的新一期是否已經出版了。如果不是這樣,你就得走回家,然後再試一次,這是一件效率低下的可悲事情。在 JavaScript 術語中,這與迴圈相同,直到得到所需的結果。當你最終拿到報紙的時候,你可以做你想做的事情 —— 坐下來喝杯咖啡,享受你的報紙(或者,對 JavaScript 術語來說,執行你一直想做的回撥函式)。

最後

明智的做法是(每天獲得你喜愛的報紙)訂閱這份報紙。這樣,出版公司就會讓你知道新一期的報紙什麼時候出版,然後把它寄給你。不再跑去報攤。不再失望。真開心。在 JavaScript 術語中,只有在執行函式之後,才會迴圈並請求結果。相反,你應該讓主題知道你對事件(訊息)感興趣,並提供一個回撥函式,應該在新資料準備好時呼叫該函式。那麼,你就是觀察者。

再也不要錯過你的晨報了。

這樣的好處是 —— 你不必是唯一的訂閱者。你會因為錯過報紙而失望,其他人也會。這就是為什麼多個觀察者可以訂閱主題。

為什麼

觀察者模式有很多用例,但是通常,當你想要在物件之間建立一對多的依賴關係時,應該使用它,這種依賴關係不是緊密耦合的,並且有可能讓數量不限的物件知道狀態何時發生了變化。

JavaScript 環境是實現觀察者模式的好地方,因為一切都是由事件驅動的,而不是總是詢問是否發生了事件,你應該讓事件通知你(就像老話說的那樣“不要給我們打電話,我們會給你打電話”)。很可能你已經完成了類似於觀察者模式的操作 —— addEventListener。向具有觀察者模式的所有標記元素新增事件監聽器:

  • 你可以訂閱這個物件,
  • 你可以取消訂閱物件,
  • 並且該物件可以向其所有訂閱者廣播事件。

學習觀察者模式的最大好處是,你可以實現自己的主題,或者更快地掌握現有的解決方案。

用在哪裡

實現一個基本的可觀察物件應該不會太難,但是有一個很棒的庫被許多專案使用,ReactiveX(它是 RxJS 對應的 JavaScript 庫)。

RxJS 不僅允許你訂閱主題,而且還允許你以可以想象的任何方式轉換資料,組合多個訂閱,使非同步工作更易於管理,而且要多得多。如果你曾經想將資料處理和轉換級別提升到更高的級別,那麼 RxJS 將是一個非常值得學習的庫。

除了觀察者模式之外,ReactiveX 還以實現了迭代器模式而自豪,該模式使主題能夠讓其訂閱者知道訂閱何時結束,從而有效地從主題的角度結束訂閱。在本文中,我不打算解釋迭代器模式,但是對於你來說,瞭解它並知道它如何適應可觀察的模式將是一個很好的練習。

外觀模式

概念

外觀模式的名稱來源於建築學。在建築學中:

外觀通常是指建築物的一面,通常是正面。這是一個來自法語的外來詞,意思是"正面"或"臉"。

正如和建築的正面作為建築物的外觀隱藏其內部運作一樣,外觀模式在軟體開發中也試圖隱藏背後的潛在複雜性,從而允許你有效地使用更容易掌握的 API,同時提供更改底層程式碼的可能性。

為什麼

你可以在許多情況下使用外觀模式,但最值得注意的是使程式碼更容易理解(隱藏複雜性),並使依賴關係儘可能鬆散耦合。

Fus Ro Dah!

很容易看出為什麼外觀模式的物件(或包含多個物件的層)是一件很棒的事情。如果可以避免的話,你肯定不想和龍打交道。觀察者模式物件將為你提供一個很好的 API,並處理所有龍的詭計本身。

我們在這裡可以做的另一件很棒的事情是在不接觸應用程式其餘部分的情況下將龍從後臺中去掉。假設你想把那條龍和一隻小貓換掉。它仍然有爪子,但更容易餵養。更改它是在不更改任何依賴物件的情況下在外觀中重寫程式碼的問題。

用在哪裡

你經常可以看到外觀模式的地方是 Angular,它使用其服務作為簡化背後潛在邏輯的一種方法。但是並不只 Angular 裡有,在下一個例子中你會看到。

假設你想要將狀態管理新增到應用程式中。你可以選擇 Redux、NgRx、Akita、MobX、Apollo 或者任何一個新成員,在這個程式碼塊裡到處出現。那麼,為什麼不把它們都挑出來,帶著它們去兜一圈呢?

狀態管理庫將為你提供哪些基本功能?

可能是:

  • 一種讓狀態管理器知道你想要更改狀態的方法
  • 以及獲取當前(片)狀態的方法。

聽起來還不錯。

現在,以你掌握的外觀模式的能力,你可以為狀態的每個部分編寫外觀,這將為你提供一個很好的 API —— 比如 facade.startSpinner()facade.stopSpinner()facade.getSpinnerState()。這些方法真的很容易理解。

在此之後,你可以處理外觀並編寫程式碼,那段程式碼將轉換你的程式碼,以便與 Apollo 一起工作(使用 GraphQL 管理狀態——現在非常流行)。你可能會注意到它根本不適合你的編碼風格,或者必須編寫單元測試的方式真的不是你喜歡的。沒問題,編寫一個新的外觀來支援 MobX。

也可能是龍……

擴充

您可能已經注意到,我所討論的設計模式沒有程式碼和實現。這是因為每一種設計模式都至少可以成為一本書的一章。

既然我們在討論書籍,那麼深入研究一兩種設計模式也無妨。

首先強烈推薦的書必須是《設計模式:可重用物件導向軟體的元素》,作者是 Erich GammaRichard HelmRalph JohnsonJohn Vlisside,也稱為四人幫。這本書價值連城,是實際意義上的軟體設計模式聖經。

如果你想找一些更容易理解的東西,可以參考 Bert BatesKathy SierraEric FreemanElisabeth Robson《Head First 設計模式》。這是一本非常好的書,它試圖通過視覺角度傳達設計模式的概念。

最後但同樣重要的是,沒有什麼比搜尋谷歌,閱讀和嘗試不同的方法更好的了。即使你最終從未使用過一種模式或技術,你也會學到一些東西,並以意想不到的方式成長。

插圖中使用的對話氣泡是由 starline — www.freepik.com 創作的。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章