偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

如何寫出優(yōu)雅的 JS 代碼?使用 SOLID 原則

開發(fā) 前端
設(shè)計模式的六個原則的首字母聯(lián)合起來(兩個 L 算做一個)就是 SOLID (solid,穩(wěn)定的),其代表的含義就是這六個原則結(jié)合使用的好處:建立穩(wěn)定、靈活、健壯的設(shè)計。下面我們來分別看一下這六大設(shè)計原則。

本文轉(zhuǎn)載自微信公眾號「大遷世界」,轉(zhuǎn)載本文請聯(lián)系大遷世界公眾號。

設(shè)計模式的六大原則有:

  • Single Responsibility Principle:單一職責原則
  • Open Closed Principle:開閉原則
  • Liskov Substitution Principle:里氏替換原則
  • Law of Demeter:迪米特法則
  • Interface Segregation Principle:接口隔離原則
  • Dependence Inversion Principle:依賴倒置原則

把這六個原則的首字母聯(lián)合起來(兩個 L 算做一個)就是 SOLID (solid,穩(wěn)定的),其代表的含義就是這六個原則結(jié)合使用的好處:建立穩(wěn)定、靈活、健壯的設(shè)計。下面我們來分別看一下這六大設(shè)計原則。

[[326031]]

單一職責原則(SRP)

單一功能原則 :單一功能原則 認為對象應該僅具有一種單一功能的概念。

換句話說就是讓一個類只做一種類型責任,當這個類需要承擔其他類型的責任的時候,就需要分解這個類。在所有的SOLID原則中,這是大多數(shù)開發(fā)人員感到最能完全理解的一條。嚴格來說,這也可能是違反最頻繁的一條原則了。單一責任原則可以看作是低耦合、高內(nèi)聚在面向?qū)ο笤瓌t上的引申,將責任定義為引起變化的原因,以提高內(nèi)聚性來減少引起變化的原因。責任過多,可能引起它變化的原因就越多,這將導致責任依賴,相互之間就產(chǎn)生影響,從而極大的損傷其內(nèi)聚性和耦合度。單一責任,通常意味著單一的功能,因此不要為一個模塊實 現(xiàn)過多的功能點,以保證實體只有一個引起它變化的原因。

「不好的寫法」

  1. class UserSettings { 
  2.   constructor(user) { 
  3.     this.user = user; 
  4.   } 
  5.  
  6.   changeSettings(settings) { 
  7.     if (this.verifyCredentials()) { 
  8.       // ... 
  9.     } 
  10.   } 
  11.  
  12.   verifyCredentials() { 
  13.     // ... 
  14.   } 

「好的寫法」

  1. class UserAuth { 
  2.   constructor(user) { 
  3.     this.user = user; 
  4.   } 
  5.  
  6.   verifyCredentials() { 
  7.     // ... 
  8.   } 
  9.  
  10. class UserSettings { 
  11.   constructor(user) { 
  12.     this.user = user; 
  13.     this.auth = new UserAuth(user); 
  14.   } 
  15.  
  16.   changeSettings(settings) { 
  17.     if (this.auth.verifyCredentials()) { 
  18.       // ... 
  19.     } 
  20.   } 

開放閉合原則 (OCP)

軟件實體應該是可擴展,而不可修改的。也就是說,對擴展是開放的,而對修改是封閉的。這個原則是諸多面向?qū)ο缶幊淘瓌t中最抽象、最難理解的一個。

  • 通過增加代碼來擴展功能,而不是修改已經(jīng)存在的代碼。
  • 若客戶模塊和服務模塊遵循同一個接口來設(shè)計,則客戶模塊可以不關(guān)心服務模塊的類型,服務模塊可以方便擴展服務(代碼)。
  • OCP支持替換的服務,而不用修改客戶模塊。

說大白話就是:你不是要變化嗎?,那么我就讓你繼承實現(xiàn)一個對象,用一個接口來抽象你的職責,你變化越多,繼承實現(xiàn)的子類就越多。

「不好的寫法」

  1. class AjaxAdapter extends Adapter { 
  2.   constructor() { 
  3.     super(); 
  4.     this.name = "ajaxAdapter"
  5.   } 
  6.  
  7. class NodeAdapter extends Adapter { 
  8.   constructor() { 
  9.     super(); 
  10.     this.name = "nodeAdapter"
  11.   } 
  12.  
  13. class HttpRequester { 
  14.   constructor(adapter) { 
  15.     this.adapter = adapter; 
  16.   } 
  17.  
  18.   fetch(url) { 
  19.     if (this.adapter.name === "ajaxAdapter") { 
  20.       return makeAjaxCall(url).then(response => { 
  21.         // transform response and return 
  22.       }); 
  23.     } else if (this.adapter.name === "nodeAdapter") { 
  24.       return makeHttpCall(url).then(response => { 
  25.         // transform response and return 
  26.       }); 
  27.     } 
  28.   } 
  29.  
  30. function makeAjaxCall(url) { 
  31.   // request and return promise 
  32.  
  33. function makeHttpCall(url) { 
  34.   // request and return promise 

「好的寫法」

  1. class AjaxAdapter extends Adapter { 
  2.   constructor() { 
  3.     super(); 
  4.     this.name = "ajaxAdapter"
  5.   } 
  6.  
  7.   request(url) { 
  8.     // request and return promise 
  9.   } 
  10.  
  11. class NodeAdapter extends Adapter { 
  12.   constructor() { 
  13.     super(); 
  14.     this.name = "nodeAdapter"
  15.   } 
  16.  
  17.   request(url) { 
  18.     // request and return promise 
  19.   } 
  20.  
  21. class HttpRequester { 
  22.   constructor(adapter) { 
  23.     this.adapter = adapter; 
  24.   } 
  25.  
  26.   fetch(url) { 
  27.     return this.adapter.request(url).then(response => { 
  28.       // transform response and return 
  29.     }); 
  30.   } 

里氏替換原則(LSP)

里氏替換原則 :里氏替換原則 認為“程序中的對象應該是可以在不改變程序正確性的前提下被它的子類所替換的”的概念。

LSP則給了我們一個判斷和設(shè)計類之間關(guān)系的基準:需不需 要繼承,以及怎樣設(shè)計繼承關(guān)系。

當一個子類的實例應該能夠替換任何其超類的實例時,它們之間才具有is-A關(guān)系。繼承對于「OCP」,就相當于多態(tài)性對于里氏替換原則。子類可以代替基類,客戶使用基類,他們不需要知道派生類所做的事情。這是一個針對行為職責可替代的原則,如果S是T的子類型,那么S對象就應該在不改變?nèi)魏纬橄髮傩郧闆r下替換所有T對象。

客戶模塊不應關(guān)心服務模塊的是如何工作的;同樣的接口模塊之間,可以在不知道服務模塊代碼的情況下,進行替換。即接口或父類出現(xiàn)的地方,實現(xiàn)接口的類或子類可以代入。

「不好的寫法」

  1. class Rectangle { 
  2.   constructor() { 
  3.     this.width = 0
  4.     this.height = 0
  5.   } 
  6.  
  7.   setColor(color) { 
  8.     // ... 
  9.   } 
  10.  
  11.   render(area) { 
  12.     // ... 
  13.   } 
  14.  
  15.   setWidth(width) { 
  16.     this.width = width; 
  17.   } 
  18.  
  19.   setHeight(height) { 
  20.     this.height = height; 
  21.   } 
  22.  
  23.   getArea() { 
  24.     return this.width * this.height; 
  25.   } 
  26.  
  27. class Square extends Rectangle { 
  28.   setWidth(width) { 
  29.     this.width = width; 
  30.     this.height = width
  31.   } 
  32.  
  33.   setHeight(height) { 
  34.     this.width = height
  35.     this.height = height; 
  36.   } 
  37.  
  38. function renderLargeRectangles(rectangles) { 
  39.   rectangles.forEach(rectangle => { 
  40.     rectangle.setWidth(4); 
  41.     rectangle.setHeight(5); 
  42.     const area = rectangle.getArea(); // BAD: Returns 25 for Square. Should be 20. 
  43.     rectangle.render(area); 
  44.   }); 
  45.  
  46. const rectangles = [new Rectangle(), new Rectangle(), new Square()]; 
  47. renderLargeRectangles(rectangles); 

「好的寫法」

  1. class Shape { 
  2.   setColor(color) { 
  3.     // ... 
  4.   } 
  5.  
  6.   render(area) { 
  7.     // ... 
  8.   } 
  9.  
  10. class Rectangle extends Shape { 
  11.   constructor(width, height) { 
  12.     super(); 
  13.     this.width = width; 
  14.     this.height = height; 
  15.   } 
  16.  
  17.   getArea() { 
  18.     return this.width * this.height; 
  19.   } 
  20.  
  21. class Square extends Shape { 
  22.   constructor(length) { 
  23.     super(); 
  24.     this.length = length; 
  25.   } 
  26.  
  27.   getArea() { 
  28.     return this.length * this.length; 
  29.   } 
  30.  
  31. function renderLargeShapes(shapes) { 
  32.   shapes.forEach(shape => { 
  33.     const area = shape.getArea(); 
  34.     shape.render(area); 
  35.   }); 
  36.  
  37. const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)]; 
  38. renderLargeShapes(shapes); 

接口隔離原則(ISP)

接口隔離原則 :接口隔離原則 認為“多個特定客戶端接口要好于一個寬泛用途的接口”的概念。

不能強迫用戶去依賴那些他們不使用的接口。換句話說,使用多個專門的接口比使用單一的總接口總要好。

這個原則起源于施樂公司,他們需要建立了一個新的打印機系統(tǒng),可以執(zhí)行諸如裝訂的印刷品一套,傳真多種任務。此系統(tǒng)軟件創(chuàng)建從底層開始編制,并實現(xiàn)了這些 任務功能,但是不斷增長的軟件功能卻使軟件本身越來越難適應變化和維護。每一次改變,即使是最小的變化,有人可能需要近一個小時的重新編譯和重新部署。這 是幾乎不可能再繼續(xù)發(fā)展,所以他們聘請羅伯特Robert幫助他們。他們首先設(shè)計了一個主要類Job,幾乎能夠用于實現(xiàn)所有任務功能。只要調(diào)用Job類的 一個方法就可以實現(xiàn)一個功能,Job類就變動非常大,是一個胖模型啊,對于客戶端如果只需要一個打印功能,但是其他無關(guān)打印的方法功能也和其耦合,ISP 原則建議在客戶端和Job類之間增加一個接口層,對于不同功能有不同接口,比如打印功能就是Print接口,然后將大的Job類切分為繼承不同接口的子 類,這樣有一個Print Job類,等等。

「不好的寫法」

  1. class DOMTraverser { 
  2.   constructor(settings) { 
  3.     this.settings = settings; 
  4.     this.setup(); 
  5.   } 
  6.  
  7.   setup() { 
  8.     thisthis.rootNode = this.settings.rootNode; 
  9.     this.animationModule.setup(); 
  10.   } 
  11.  
  12.   traverse() { 
  13.     // ... 
  14.   } 
  15.  
  16. const $ = new DOMTraverser({ 
  17.   rootNode: document.getElementsByTagName("body"), 
  18.   animationModule() {} // Most of the time, we won't need to animate when traversing. 
  19.   // ... 
  20. }); 

「好的寫法」

  1. class DOMTraverser { 
  2.   constructor(settings) { 
  3.     this.settings = settings; 
  4.     this.options = settings.options; 
  5.     this.setup(); 
  6.   } 
  7.  
  8.   setup() { 
  9.     thisthis.rootNode = this.settings.rootNode; 
  10.     this.setupOptions(); 
  11.   } 
  12.  
  13.   setupOptions() { 
  14.     if (this.options.animationModule) { 
  15.       // ... 
  16.     } 
  17.   } 
  18.  
  19.   traverse() { 
  20.     // ... 
  21.   } 
  22.  
  23. const $ = new DOMTraverser({ 
  24.   rootNode: document.getElementsByTagName("body"), 
  25.   options: { 
  26.     animationModule() {} 
  27.   } 
  28. }); 

依賴倒置原則(DIP)

依賴倒置原則:依賴倒置原則 認為一個方法應該遵從“依賴于抽象而不是一個實例” 的概念。依賴注入是該原則的一種實現(xiàn)方式。

依賴倒置原則(Dependency Inversion Principle,DIP)規(guī)定:代碼應當取決于抽象概念,而不是具體實現(xiàn)。

  • 高層模塊不要依賴低層模塊
  • 高層和低層模塊都要依賴于抽象;
  • 抽象不要依賴于具體實現(xiàn)
  • 具體實現(xiàn)要依賴于抽象
  • 抽象和接口使模塊之間的依賴分離

類可能依賴于其他類來執(zhí)行其工作。但是,它們不應當依賴于該類的特定具體實現(xiàn),而應當是它的抽象。這個原則實在是太重要了,社會的分工化,標準化都 是這個設(shè)計原則的體現(xiàn)。顯然,這一概念會大大提高系統(tǒng)的靈活性。如果類只關(guān)心它們用于支持特定契約而不是特定類型的組件,就可以快速而輕松地修改這些低級 服務的功能,同時最大限度地降低對系統(tǒng)其余部分的影響。

「不好的寫法」

  1. class InventoryRequester { 
  2.   constructor() { 
  3.     this.REQ_METHODS = ["HTTP"]; 
  4.   } 
  5.  
  6.   requestItem(item) { 
  7.     // ... 
  8.   } 
  9.  
  10. class InventoryTracker { 
  11.   constructor(items) { 
  12.     this.items = items; 
  13.  
  14.     // BAD: We have created a dependency on a specific request implementation. 
  15.     // We should just have requestItems depend on a request method: `request` 
  16.     this.requester = new InventoryRequester(); 
  17.   } 
  18.  
  19.   requestItems() { 
  20.     this.items.forEach(item => { 
  21.       this.requester.requestItem(item); 
  22.     }); 
  23.   } 
  24.  
  25. const inventoryTracker = new InventoryTracker(["apples", "bananas"]); 
  26. inventoryTracker.requestItems(); 

「好的寫法」

  1. class InventoryTracker { 
  2.   constructor(items, requester) { 
  3.     this.items = items; 
  4.     this.requester = requester; 
  5.   } 
  6.  
  7.   requestItems() { 
  8.     this.items.forEach(item => { 
  9.       this.requester.requestItem(item); 
  10.     }); 
  11.   } 
  12.  
  13. class InventoryRequesterV1 { 
  14.   constructor() { 
  15.     this.REQ_METHODS = ["HTTP"]; 
  16.   } 
  17.  
  18.   requestItem(item) { 
  19.     // ... 
  20.   } 
  21.  
  22. class InventoryRequesterV2 { 
  23.   constructor() { 
  24.     this.REQ_METHODS = ["WS"]; 
  25.   } 
  26.  
  27.   requestItem(item) { 
  28.     // ... 
  29.   } 
  30. const inventoryTracker = new InventoryTracker( 
  31.   ["apples", "bananas"], 
  32.   new InventoryRequesterV2() 
  33. ); 
  34. inventoryTracker.requestItems(); 

 

責任編輯:趙寧寧 來源: 大遷世界
相關(guān)推薦

2021-01-04 07:57:07

C++工具代碼

2019-09-20 15:47:24

代碼JavaScript副作用

2022-03-11 12:14:43

CSS代碼前端

2020-05-08 14:45:00

JS代碼變量

2021-12-07 08:16:34

React 前端 組件

2020-07-15 08:17:16

代碼

2020-05-11 15:23:58

CQRS代碼命令

2021-09-01 08:55:20

JavaScript代碼開發(fā)

2013-06-07 14:00:23

代碼維護

2021-11-30 10:20:24

JavaScript代碼前端

2022-02-08 19:33:13

技巧代碼格式

2022-02-17 10:05:21

CSS代碼前端

2020-12-19 10:45:08

Python代碼開發(fā)

2020-05-19 15:00:26

Bug代碼語言

2021-12-13 14:37:37

React組件前端

2017-10-24 15:28:27

PHP代碼簡潔SOLID原則

2022-09-27 09:21:34

SOLID開閉原則Go

2022-10-24 08:10:21

SQL代碼業(yè)務

2015-09-28 10:49:59

代碼程序員

2019-06-24 10:26:15

代碼程序注釋
點贊
收藏

51CTO技術(shù)棧公眾號