溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

JS設(shè)計(jì)模式的六大原則是什么

發(fā)布時(shí)間:2021-11-03 13:41:33 來(lái)源:億速云 閱讀:143 作者:iii 欄目:web開(kāi)發(fā)

本篇內(nèi)容主要講解“JS設(shè)計(jì)模式的六大原則是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“JS設(shè)計(jì)模式的六大原則是什么”吧!

單一職責(zé)原則(SRP)

單一功能原則 :?jiǎn)我还δ茉瓌t 認(rèn)為對(duì)象應(yīng)該僅具有一種單一功能的概念。

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

「不好的寫(xiě)法」

class UserSettings {   constructor(user) {     this.user = user;   }    changeSettings(settings) {     if (this.verifyCredentials()) {       // ...     }   }    verifyCredentials() {     // ...   } }

「好的寫(xiě)法」

class UserAuth {   constructor(user) {     this.user = user;   }    verifyCredentials() {     // ...   } }  class UserSettings {   constructor(user) {     this.user = user;     this.auth = new UserAuth(user);   }    changeSettings(settings) {     if (this.auth.verifyCredentials()) {       // ...     }   } }

開(kāi)放閉合原則 (OCP)

軟件實(shí)體應(yīng)該是可擴(kuò)展,而不可修改的。也就是說(shuō),對(duì)擴(kuò)展是開(kāi)放的,而對(duì)修改是封閉的。這個(gè)原則是諸多面向?qū)ο缶幊淘瓌t中最抽象、最難理解的一個(gè)。

  • 通過(guò)增加代碼來(lái)擴(kuò)展功能,而不是修改已經(jīng)存在的代碼。

  • 若客戶(hù)模塊和服務(wù)模塊遵循同一個(gè)接口來(lái)設(shè)計(jì),則客戶(hù)模塊可以不關(guān)心服務(wù)模塊的類(lèi)型,服務(wù)模塊可以方便擴(kuò)展服務(wù)(代碼)。

  • OCP支持替換的服務(wù),而不用修改客戶(hù)模塊。

說(shuō)大白話就是:你不是要變化嗎?,那么我就讓你繼承實(shí)現(xiàn)一個(gè)對(duì)象,用一個(gè)接口來(lái)抽象你的職責(zé),你變化越多,繼承實(shí)現(xiàn)的子類(lèi)就越多。

「不好的寫(xiě)法」

class AjaxAdapter extends Adapter {   constructor() {     super();     this.name = "ajaxAdapter";   } }  class NodeAdapter extends Adapter {   constructor() {     super();     this.name = "nodeAdapter";   } }  class HttpRequester {   constructor(adapter) {     this.adapter = adapter;   }    fetch(url) {     if (this.adapter.name === "ajaxAdapter") {       return makeAjaxCall(url).then(response => {         // transform response and return       });     } else if (this.adapter.name === "nodeAdapter") {       return makeHttpCall(url).then(response => {         // transform response and return       });     }   } }  function makeAjaxCall(url) {   // request and return promise }  function makeHttpCall(url) {   // request and return promise }

「好的寫(xiě)法」

class AjaxAdapter extends Adapter {   constructor() {     super();     this.name = "ajaxAdapter";   }    request(url) {     // request and return promise   } }  class NodeAdapter extends Adapter {   constructor() {     super();     this.name = "nodeAdapter";   }    request(url) {     // request and return promise   } }  class HttpRequester {   constructor(adapter) {     this.adapter = adapter;   }    fetch(url) {     return this.adapter.request(url).then(response => {       // transform response and return     });   } }

里氏替換原則(LSP)

里氏替換原則 :里氏替換原則 認(rèn)為“程序中的對(duì)象應(yīng)該是可以在不改變程序正確性的前提下被它的子類(lèi)所替換的”的概念。

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

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

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

「不好的寫(xiě)法」

class Rectangle {   constructor() {     this.width = 0;     this.height = 0;   }    setColor(color) {     // ...   }    render(area) {     // ...   }    setWidth(width) {     this.width = width;   }    setHeight(height) {     this.height = height;   }    getArea() {     return this.width * this.height;   } }  class Square extends Rectangle {   setWidth(width) {     this.width = width;     this.height = width;   }    setHeight(height) {     this.width = height;     this.height = height;   } }  function renderLargeRectangles(rectangles) {   rectangles.forEach(rectangle => {     rectangle.setWidth(4);     rectangle.setHeight(5);     const area = rectangle.getArea(); // BAD: Returns 25 for Square. Should be 20.     rectangle.render(area);   }); }  const rectangles = [new Rectangle(), new Rectangle(), new Square()]; renderLargeRectangles(rectangles);

「好的寫(xiě)法」

class Shape {   setColor(color) {     // ...   }    render(area) {     // ...   } }  class Rectangle extends Shape {   constructor(width, height) {     super();     this.width = width;     this.height = height;   }    getArea() {     return this.width * this.height;   } }  class Square extends Shape {   constructor(length) {     super();     this.length = length;   }    getArea() {     return this.length * this.length;   } }  function renderLargeShapes(shapes) {   shapes.forEach(shape => {     const area = shape.getArea();     shape.render(area);   }); }  const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)]; renderLargeShapes(shapes);

接口隔離原則(ISP)

接口隔離原則 :接口隔離原則 認(rèn)為“多個(gè)特定客戶(hù)端接口要好于一個(gè)寬泛用途的接口”的概念。

不能強(qiáng)迫用戶(hù)去依賴(lài)那些他們不使用的接口。換句話說(shuō),使用多個(gè)專(zhuān)門(mén)的接口比使用單一的總接口總要好。

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

「不好的寫(xiě)法」

class DOMTraverser {   constructor(settings) {     this.settings = settings;     this.setup();   }    setup() {     thisthis.rootNode = this.settings.rootNode;     this.animationModule.setup();   }    traverse() {     // ...   } }  const $ = new DOMTraverser({   rootNode: document.getElementsByTagName("body"),   animationModule() {} // Most of the time, we won't need to animate when traversing.   // ... });

「好的寫(xiě)法」

class DOMTraverser {   constructor(settings) {     this.settings = settings;     this.options = settings.options;     this.setup();   }    setup() {     thisthis.rootNode = this.settings.rootNode;     this.setupOptions();   }    setupOptions() {     if (this.options.animationModule) {       // ...     }   }    traverse() {     // ...   } }  const $ = new DOMTraverser({   rootNode: document.getElementsByTagName("body"),   options: {     animationModule() {}   } });

依賴(lài)倒置原則(DIP)

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

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

  • 高層模塊不要依賴(lài)低層模塊

  • 高層和低層模塊都要依賴(lài)于抽象;

  • 抽象不要依賴(lài)于具體實(shí)現(xiàn)

  • 具體實(shí)現(xiàn)要依賴(lài)于抽象

  • 抽象和接口使模塊之間的依賴(lài)分離

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

「不好的寫(xiě)法」

class InventoryRequester {   constructor() {     this.REQ_METHODS = ["HTTP"];   }    requestItem(item) {     // ...   } }  class InventoryTracker {   constructor(items) {     this.items = items;      // BAD: We have created a dependency on a specific request implementation.     // We should just have requestItems depend on a request method: `request`     this.requester = new InventoryRequester();   }    requestItems() {     this.items.forEach(item => {       this.requester.requestItem(item);     });   } }  const inventoryTracker = new InventoryTracker(["apples", "bananas"]); inventoryTracker.requestItems();

「好的寫(xiě)法」

class InventoryTracker {   constructor(items, requester) {     this.items = items;     this.requester = requester;   }    requestItems() {     this.items.forEach(item => {       this.requester.requestItem(item);     });   } }  class InventoryRequesterV1 {   constructor() {     this.REQ_METHODS = ["HTTP"];   }    requestItem(item) {     // ...   } }  class InventoryRequesterV2 {   constructor() {     this.REQ_METHODS = ["WS"];   }    requestItem(item) {     // ...   } } const inventoryTracker = new InventoryTracker(   ["apples", "bananas"],   new InventoryRequesterV2() ); inventoryTracker.requestItems();

到此,相信大家對(duì)“JS設(shè)計(jì)模式的六大原則是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI