您好,登錄后才能下訂單哦!
本篇內(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í)!
免責(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)容。