欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript設(shè)計(jì)模式之策略模式詳解

 更新時(shí)間:2022年06月27日 09:10:36   作者:天行無(wú)忌  
設(shè)計(jì)模式(Design pattern)是解決軟件開(kāi)發(fā)某些特定問(wèn)題而提出的一些解決方案也可以理解成解決問(wèn)題的一些思路,下面這篇文章主要給大家介紹了關(guān)于JavaScript設(shè)計(jì)模式之策略模式的相關(guān)資料,需要的朋友可以參考下

什么是設(shè)計(jì)模式?為什么需要學(xué)習(xí)設(shè)計(jì)模式?

學(xué)習(xí)設(shè)計(jì)模式的目的是:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設(shè)計(jì)模式使代碼編寫(xiě)真正工程化;設(shè)計(jì)模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。

經(jīng)典的設(shè)計(jì)模式有 23 種,但并不是每一種設(shè)計(jì)模式都被頻繁使用。在這里,介紹最常用和最實(shí)用的幾種設(shè)計(jì)模式,本文先來(lái)介紹策略模式(Strategy Pattern)。

策略模式是一種行為設(shè)計(jì)模式,定義一系列算法,將每一個(gè)算法封裝起來(lái),并讓它們可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而變化,也稱為政策模式(Policy)。

假如正在開(kāi)發(fā)一個(gè)在線商城的項(xiàng)目,每個(gè)產(chǎn)品都有原價(jià),稱之為 originalPrice。但實(shí)際上并非所有產(chǎn)品都以原價(jià)出售,可能會(huì)推出允許以折扣價(jià)出售商品的促銷活動(dòng)。

商家可以在后臺(tái)為產(chǎn)品設(shè)置不同的狀態(tài),然后實(shí)際售價(jià)將根據(jù)產(chǎn)品狀態(tài)和原價(jià)動(dòng)態(tài)調(diào)整。

具體規(guī)則如下:

  • 部分產(chǎn)品已預(yù)售:為鼓勵(lì)客戶預(yù)訂,將在原價(jià)基礎(chǔ)上享受 20% 的折扣。
  • 部分產(chǎn)品處于正常促銷階段:如果原價(jià)低于或等于100,則以10%的折扣出售;如果原價(jià)高于 100,則減 10 元。
  • 有些產(chǎn)品沒(méi)有任何促銷活動(dòng):它們屬于 default 狀態(tài),并以原價(jià)出售。

這時(shí)需要寫(xiě)一個(gè)獲取商品價(jià)格的函數(shù) getPrice ,應(yīng)該怎么寫(xiě)呢?

function getPrice(originalPrice, status) {
    // ...
    // 返回價(jià)格;
}

事實(shí)上,面對(duì)這樣的問(wèn)題,如果不考慮任何設(shè)計(jì)模式,最直觀的寫(xiě)法可能 if-else 多次條件判斷語(yǔ)句來(lái)計(jì)算價(jià)格。

有三種狀態(tài),可以快速編寫(xiě)如下代碼:

function getPrice(originalPrice, status) {
    if (status === "pre-sale") {
        return originalPrice * 0.8;
    }

    if (status === "promotion") {
        if (origialPrice <= 100) {
            return origialPrice * 0.9;
        } else {
            return originalPrice - 20;
        }
    }

    if (status === "default") {
        return originalPrice;
    }
}

有三個(gè)條件,上面的代碼寫(xiě)了三個(gè) if 語(yǔ)句,這是非常直觀的代碼,但是這段代碼組織上不好。

首先,它違反了單一職責(zé)原則(Single responsibility principle,規(guī)定每個(gè)類或者函數(shù)都應(yīng)該有一個(gè)單一的功能,并且該功能應(yīng)該由這個(gè)類或者函數(shù)完全封裝起來(lái))。函數(shù) getPrice 做了太多的事情,這個(gè)函數(shù)不易閱讀,也容易出現(xiàn) bug 。如果一個(gè)條件出現(xiàn) bug ,整個(gè)函數(shù)就會(huì)崩潰。同時(shí),這樣的代碼也不容易調(diào)試。

并且這段代碼很難應(yīng)對(duì)變化的需求,這時(shí)就需要考慮設(shè)計(jì)模式,其往往會(huì)在業(yè)務(wù)邏輯發(fā)生變化時(shí)展現(xiàn)出它的魅力。

假設(shè)業(yè)務(wù)擴(kuò)大了,現(xiàn)在還有另一個(gè)折扣促銷:黑色星期五。折扣規(guī)則如下:

  • 價(jià)格低于或等于 100 元的產(chǎn)品以 20% 的折扣出售。
  • 價(jià)格高于 100 元但低于 200 元的產(chǎn)品將減少 20 元。
  • 價(jià)格高于或等于 200 元的產(chǎn)品將減少 20 元。

這個(gè)時(shí)候該怎么擴(kuò)展 getPrice 函數(shù)呢?

看起來(lái)必須在 getPrice 函數(shù)中添加一個(gè)條件語(yǔ)句:

function getPrice(originalPrice, status) {
    if (status === "pre-sale") {
        return originalPrice * 0.8;
    }

    if (status === "promotion") {
        if (origialPrice <= 100) {
            return origialPrice * 0.9;
        } else {
            return originalPrice - 20;
        }
    }
    // 黑色星期五規(guī)則
    if (status === "black-friday") {
        if (origialPrice >= 100 && originalPrice < 200) {
            return origialPrice - 20;
        } else if (originalPrice >= 200) {
            return originalPrice - 50;
        } else {
            return originalPrice * 0.8;
        }
    }

    if (status === "default") {
        return originalPrice;
    }
}

每當(dāng)增加或減少折扣時(shí),都需要更改函數(shù)。這種做法違反了開(kāi)閉原則(對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉)。修改已有的功能很容易出現(xiàn)新的錯(cuò)誤,而且還會(huì)使得 getPrice 越來(lái)越臃腫。

那么如何優(yōu)化這段代碼呢?

首先,可以拆分這個(gè)函數(shù) getPrice 以減少臃腫。

/**
 * 預(yù)售商品價(jià)格規(guī)則
 * @param {*} origialPrice
 * @returns
 */
function preSalePrice(origialPrice) {
    return originalPrice * 0.8;
}
/**
 * 促銷商品價(jià)格規(guī)則
 * @param {*} origialPrice
 * @returns
 */
function promotionPrice(origialPrice) {
    if (origialPrice <= 100) {
        return origialPrice * 0.9;
    } else {
        return originalPrice - 20;
    }
}
/**
 * 黑色星期五促銷規(guī)則
 * @param {*} origialPrice
 * @returns
 */
function blackFridayPrice(origialPrice) {
    if (origialPrice >= 100 && originalPrice < 200) {
        return origialPrice - 20;
    } else if (originalPrice >= 200) {
        return originalPrice - 50;
    } else {
        return originalPrice * 0.8;
    }
}
/**
 * 默認(rèn)商品價(jià)格
 * @param {*} origialPrice
 * @returns
 */
function defaultPrice(origialPrice) {
    return origialPrice;
}

function getPrice(originalPrice, status) {
    if (status === "pre-sale") {
        return preSalePrice(originalPrice);
    }

    if (status === "promotion") {
        return promotionPrice(originalPrice);
    }

    if (status === "black-friday") {
        return blackFridayPrice(originalPrice);
    }

    if (status === "default") {
        return defaultPrice(originalPrice);
    }
}

經(jīng)過(guò)這次修改,雖然代碼行數(shù)增加了,但是可讀性有了明顯的提升。getPrice 函數(shù)顯然沒(méi)有那么臃腫,寫(xiě)單元測(cè)試也比較方便。

但是上面的改動(dòng)并沒(méi)有解決根本的問(wèn)題:代碼還是充滿了 if-else ,而且當(dāng)增加或者減少折扣規(guī)則的時(shí)候,仍然需要修改 getPrice。

其實(shí)使用這些 if-else 的目的就是為了對(duì)應(yīng)狀態(tài)和折扣策略。

從圖中可以發(fā)現(xiàn),這個(gè)邏輯本質(zhì)上是一種映射關(guān)系:產(chǎn)品狀態(tài)與折扣策略的映射關(guān)系。

可以使用映射而不是冗長(zhǎng)的 if-else 來(lái)存儲(chǔ)映射,按照這個(gè)思路可以構(gòu)造一個(gè)價(jià)格策略的映射關(guān)系(策略名稱與其處理函數(shù)之間的映射),如下:

const priceStrategies = {
    "pre-sale": preSalePrice,
    promotion: promotionPrice,
    "black-friday": blackFridayPrice,
    default: defaultPrice,
};

將狀態(tài)與折扣策略結(jié)合起來(lái),價(jià)格函數(shù)就可以優(yōu)化成如下:

function getPrice(originalPrice, status) {
    return priceStrategies[status](originalPrice);
}

這時(shí)候如果需要加減折扣策略,不需要修改函數(shù),只需要修改價(jià)格策略映射關(guān)系 priceStrategies

之前的代碼邏輯如下:

優(yōu)化后的代碼邏輯如下:

以上的優(yōu)化策略就是使用了設(shè)計(jì)模式之策略模式,在實(shí)際的項(xiàng)目開(kāi)發(fā)過(guò)程中還是比較實(shí)用。

在什么情況下可以考慮使用策略模式呢?如果函數(shù)具有以下特征:

  • 判斷條件很多
  • 各個(gè)判斷條件下的代碼相互獨(dú)立

然后可以將每個(gè)判斷條件下的代碼封裝成一個(gè)獨(dú)立的函數(shù),然后建立判斷條件和具體策略的映射關(guān)系。

總結(jié)

到此這篇關(guān)于JavaScript設(shè)計(jì)模式之策略模式的文章就介紹到這了,更多相關(guān)JavaScript策略模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 探索瀏覽器頁(yè)面關(guān)閉window.close()的使用詳解

    探索瀏覽器頁(yè)面關(guān)閉window.close()的使用詳解

    這篇文章主要介紹了探索瀏覽器頁(yè)面關(guān)閉window.close()的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • javascript中encodeURI和decodeURI方法使用介紹

    javascript中encodeURI和decodeURI方法使用介紹

    encodeURI和decodeURI是成對(duì)來(lái)使用的,因?yàn)闉g覽器的地址欄有中文字符的話,可以會(huì)出現(xiàn)不可預(yù)期的錯(cuò)誤,所以可以encodeURI把非英文字符轉(zhuǎn)化為英文編碼,decodeURI可以用來(lái)把字符還原回來(lái)
    2013-05-05
  • 自己使用js/jquery寫(xiě)的一個(gè)定制對(duì)話框控件

    自己使用js/jquery寫(xiě)的一個(gè)定制對(duì)話框控件

    自己做一個(gè)通用的控件,雖然不是絕對(duì)通用啦,但在我這個(gè)項(xiàng)目里還是可以隨意調(diào)用的,思想的話也可以借鑒到別的項(xiàng)目中
    2014-05-05
  • js前端實(shí)現(xiàn)多圖圖片上傳預(yù)覽的兩個(gè)方法(推薦)

    js前端實(shí)現(xiàn)多圖圖片上傳預(yù)覽的兩個(gè)方法(推薦)

    下面小編就為大家?guī)?lái)一篇js前端實(shí)現(xiàn)多圖圖片上傳預(yù)覽的兩個(gè)方法(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • javascript中typeof操作符和constucor屬性檢測(cè)

    javascript中typeof操作符和constucor屬性檢測(cè)

    這篇文章主要介紹了javascript中typeof操作符和constucor屬性檢測(cè)的相關(guān)資料,需要的朋友可以參考下
    2015-02-02
  • 微信小程序封裝自定義彈窗的實(shí)現(xiàn)代碼

    微信小程序封裝自定義彈窗的實(shí)現(xiàn)代碼

    這篇文章主要介紹了微信小程序封裝自定義彈窗的實(shí)現(xiàn)代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05
  • 5 種JavaScript編碼規(guī)范

    5 種JavaScript編碼規(guī)范

    編碼規(guī)范就是指導(dǎo)如何編寫(xiě)和組織代碼的一系列標(biāo)準(zhǔn),下面通過(guò)本文給大家?guī)?lái)了5 種JavaScript編碼規(guī)范,需要的朋友參考下
    2018-01-01
  • JavaScript使用lodash實(shí)現(xiàn)命名轉(zhuǎn)換和函數(shù)封裝

    JavaScript使用lodash實(shí)現(xiàn)命名轉(zhuǎn)換和函數(shù)封裝

    Lodash?是一個(gè)?JavaScript?的工具庫(kù),它提供了一系列的函數(shù)來(lái)簡(jiǎn)化代碼編寫(xiě),本文主要為大家介紹了如何使用lodash實(shí)現(xiàn)命名轉(zhuǎn)換和函數(shù)封裝,感興趣的小伙伴可以了解下
    2023-11-11
  • 重構(gòu)Javascript代碼示例(重構(gòu)前后對(duì)比)

    重構(gòu)Javascript代碼示例(重構(gòu)前后對(duì)比)

    回顧頭來(lái)看看那些Javascript腳本,有寫(xiě)得不太理想,過(guò)于復(fù)雜?,F(xiàn)抽取出來(lái),重構(gòu)它們,想學(xué)習(xí)javascript重構(gòu)的朋友可以參考下啊,網(wǎng)本文可以幫助你的
    2013-01-01
  • 如何基于JS截獲動(dòng)態(tài)代碼

    如何基于JS截獲動(dòng)態(tài)代碼

    這篇文章主要介紹了JS注入eval, Function系統(tǒng)函數(shù)并截獲動(dòng)態(tài)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12

最新評(píng)論