成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前端設(shè)計(jì)模式用起來(lái)(1)狀態(tài)模式

Salamander / 3167人閱讀

摘要:有限狀態(tài)機(jī)可以歸納出四個(gè)要素現(xiàn)態(tài)即當(dāng)前的狀態(tài)。但狀態(tài)模式還有一點(diǎn)需要注意到,當(dāng)采用子類繼承實(shí)現(xiàn)多種具體狀態(tài)的時(shí)候,注意控制狀態(tài)的數(shù)量,以免出現(xiàn)子類數(shù)量膨脹的現(xiàn)象在使用或等更完整面向?qū)ο笳Z(yǔ)言時(shí)。

業(yè)務(wù)代碼開(kāi)發(fā)久了,偶爾看看設(shè)計(jì)模式,總會(huì)讓自己有一種清新脫俗的感覺(jué)??傁氚堰@種感覺(jué)記下來(lái),但一想到要先起個(gè)恰如其分的標(biāo)題和開(kāi)頭,就讓我有一種百爪撓心的糾結(jié),所以遲遲沒(méi)有開(kāi)始。今天起更新我學(xué)習(xí)設(shè)計(jì)模式筆記的原因,就好像是,你喜歡一個(gè)女孩久了,卻總不表白,難道不怕被別人截胡了么!

首先我們來(lái)一起設(shè)想一些場(chǎng)景:

程序員們?cè)诘入娞莸臅r(shí)候,聊天頻率最高的一個(gè)話題,是不是電梯調(diào)度算法呢。寫(xiě)字樓的幾部電梯到底是分單雙層運(yùn)力快,還是高低層運(yùn)力快?當(dāng)你按下電梯時(shí),是就近樓層的電梯視來(lái)接你,還是自顧自的先上后下順帶來(lái)接你?

開(kāi)車來(lái)到路口,對(duì)紅綠燈亮滅的長(zhǎng)短是否曾有過(guò)習(xí)慣性的吐槽

除了電梯調(diào)度、紅綠燈控制,軟件設(shè)計(jì)和業(yè)務(wù)開(kāi)發(fā)中,類似諸如狀態(tài)切換的問(wèn)題不難遇到。他們的共同點(diǎn)是:場(chǎng)景存在多個(gè)狀態(tài),狀態(tài)改變時(shí)會(huì)觸發(fā)對(duì)應(yīng)的不同處理方法,狀態(tài)間切換又存在諸多約束和限制。

面對(duì)這種場(chǎng)景,你腦海里的第一解決方案是什么?條件分支if...else或者switch...case么?其實(shí)應(yīng)當(dāng)視具體場(chǎng)景復(fù)雜度來(lái)看,如果狀態(tài)少邏輯簡(jiǎn)單,條件分支力所能及。但倘若狀態(tài)較多,邏輯復(fù)雜,又存在諸多特殊情況的約束限制,本文將介紹的狀態(tài)模式歡迎來(lái)解一下。

狀態(tài)模式
定義:當(dāng)一個(gè)對(duì)象的內(nèi)在狀態(tài)改變時(shí),允許改變其行為,這個(gè)對(duì)象看起來(lái)像是改變了其類

我們先來(lái)看下傳統(tǒng)面向?qū)ο笳Z(yǔ)言的類圖,后面再細(xì)說(shuō)前端js中該如何應(yīng)用

對(duì)于一個(gè)if...else處理的長(zhǎng)流程,我們可以抽象成多個(gè)狀態(tài)的切換,不同具體的狀態(tài)繼承自一個(gè)抽象狀態(tài)接口。場(chǎng)景類維護(hù)當(dāng)前狀態(tài)對(duì)象的一個(gè)實(shí)例,以及狀態(tài)切換間的約束關(guān)系。

這樣做的好處是將狀態(tài)的獲取和狀態(tài)的切換進(jìn)行了分離,一個(gè)具體的狀態(tài)類只處理本狀態(tài)相關(guān)的邏輯,符合單一職責(zé)原則,后期如果新加狀態(tài)只需要新建具體的狀態(tài)類,符合開(kāi)放封閉原則

JavaScript沒(méi)有抽象接口類的概念,所有類圖也大大簡(jiǎn)化,如下:

State類為狀態(tài)類,包含狀態(tài)值以及狀態(tài)改變時(shí)具體的處理方法。Context類為場(chǎng)景類,維護(hù)狀態(tài)間的約束關(guān)系以及控制觸發(fā)狀態(tài)的切換。
下面我們看下代碼,讓概念平穩(wěn)落地:

// 定義狀態(tài)類
class State {
    constructor(color) {
        this.color = color
    }
    // 處理該狀態(tài)下具體邏輯
    handle(context) {
        console.log(`turn to ${this.color}`)
        context.setState(this)
    }
}
// 定義場(chǎng)景類
class Context {
    constructor() {
        this.state = null
    }
    setState(state) {
        this.state = state
    }
    getState() {
        return this.state
    }
}

測(cè)試代碼如下:

const ctx = new Context()
// 實(shí)例出具體狀態(tài)
const red = new State("red")
const green = new State("green")
const yellow = new State("yellow")
// 綠燈亮
green.handle(ctx)
console.log(ctx.getState())
// 紅燈亮
red.handle(ctx)
console.log(ctx.getState())
// 黃燈亮
yellow.handle(ctx)
console.log(ctx.getState())
有限狀態(tài)機(jī)

狀態(tài)模式脫胎自有限狀態(tài)機(jī)(Finite-State-Machine),這個(gè)數(shù)學(xué)模型描述了有限個(gè)狀態(tài),以及這些狀態(tài)之間轉(zhuǎn)移和動(dòng)作的行為,是一種對(duì)象行為建模的工具。類似下圖就是一種有限狀態(tài)機(jī):

其實(shí)我們?cè)谔幚順I(yè)務(wù)邏輯時(shí),經(jīng)常打交道的各種事件和狀態(tài)切換,寫(xiě)的各種if...elseswitch...case都是有限狀態(tài)機(jī)模型,只是平時(shí)沒(méi)有意識(shí)到吧了。在處理較為復(fù)雜的邏輯時(shí),考慮把業(yè)務(wù)邏輯抽象成一個(gè)有限狀態(tài)機(jī)模型,常常會(huì)是代碼邏輯清晰,結(jié)構(gòu)規(guī)整。

有限狀態(tài)機(jī)可以歸納出四個(gè)要素:

現(xiàn)態(tài):即當(dāng)前的狀態(tài)。

條件:又稱為“事件”。當(dāng)一個(gè)條件被滿足,將會(huì)觸發(fā)一個(gè)動(dòng)作,或者執(zhí)行一次狀態(tài)的遷移。

動(dòng)作:條件滿足后執(zhí)行的動(dòng)作。動(dòng)作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。動(dòng)作不是必需的,當(dāng)條件滿足后,也可以不執(zhí)行任何動(dòng)作,直接遷移到新?tīng)顟B(tài)。

次態(tài):條件滿足后要遷往的新?tīng)顟B(tài)。次態(tài)是相對(duì)于現(xiàn)態(tài)而言的,次態(tài)一旦被激活,就轉(zhuǎn)變成新的現(xiàn)態(tài)了。

Tips:避免把某個(gè)程序動(dòng)作當(dāng)作是一種狀態(tài)來(lái)處理,動(dòng)作是不穩(wěn)定的,即使條件沒(méi)有觸發(fā),一旦動(dòng)作執(zhí)行完也就結(jié)束了;但狀態(tài)是穩(wěn)定的,如果沒(méi)有外部條件觸發(fā),狀態(tài)會(huì)一直持續(xù)下去。

介紹了有限狀態(tài)機(jī),我們當(dāng)然可以通過(guò)上面介紹的狀態(tài)模式的方式,來(lái)將這種模型工具應(yīng)用到我們的代碼開(kāi)發(fā)當(dāng)中。但是你有沒(méi)有注意到一個(gè)問(wèn)題?對(duì),代碼不夠優(yōu)雅,略顯簡(jiǎn)陋,不能忍!

接下來(lái)介紹一個(gè)優(yōu)雅的有限狀態(tài)機(jī)實(shí)現(xiàn)類庫(kù)javascript-state-machine,接下來(lái)使用這個(gè)類庫(kù)簡(jiǎn)單實(shí)現(xiàn)一個(gè)Promise的功能,來(lái)看一下如何使用。

Promise簡(jiǎn)單實(shí)現(xiàn)

首先回顧一下Promise的特點(diǎn):

Promise是一個(gè)類。

Promise在實(shí)例初始化的時(shí)候需要傳入一個(gè)函數(shù)。

傳入的函數(shù)需要接收resolvereject兩個(gè)函數(shù),成功的時(shí)候調(diào)用resolve,失敗的時(shí)候調(diào)用reject。

Promise實(shí)例出的對(duì)象有一個(gè)then方法,可以進(jìn)行鏈?zhǔn)讲僮鳌?/p>

Promise擁有三種狀態(tài):pending、fulfilled、rejected,可以從pending->fulfilled,或pending->rejected,但不能逆向。

接下來(lái)上代碼實(shí)現(xiàn)一下

// 狀態(tài)機(jī)模型
const fsm = new StateMachine({
    // 初始狀態(tài)
    init: "pending",
    // 狀態(tài)遷移規(guī)則,name,from,to的名字盡量別同名
    transitions: [
        { name: "resolve", from: "pending", to: "fulfilled" },
        { name: "reject", from: "pending", to: "rejected"}
    ],
    methods: {
        onResolve(state, data) {
            data.successFn.forEach(fn => fn())
        },
        onReject(state, data) {
            data.failFn.forEach(fn => fn())
        }
    }
})
// 定義Promise
class MyPromise {
    constructor(fn) {
        this.successFn = []
        this.failFn = []
        fn(
            () => { fsm.resolve(this)},
            () => { fsm.reject(this)}
        )
    }
    then(successFn, failFn) {
        this.successFn.push(successFn)
        this.failFn.push(failFn)
        return this
    }
}
總結(jié)

本文介紹了狀態(tài)模式和有限狀態(tài)機(jī)的概念,以及才開(kāi)發(fā)中優(yōu)雅使用的姿勢(shì)javascript-state-machine,并通過(guò)用其簡(jiǎn)單實(shí)現(xiàn)了Promise的基本功能,演示了如何使用。

其實(shí)重點(diǎn)還是狀態(tài)模式,通過(guò)本文介紹可以很明顯地感受到其優(yōu)點(diǎn):

結(jié)構(gòu)清晰,避免了過(guò)多的if...elseswitch...case的使用,降低了程序的復(fù)雜性,提高了系統(tǒng)的可維護(hù)性。

很好遵循了開(kāi)放封閉原則和單一職責(zé)原則。

記得Martin在《重構(gòu)》中,提到一個(gè)壞的代碼味道“Long Method”,當(dāng)你遇到一個(gè)方法中包含了一大堆邏輯,做了很多事的時(shí)候,你就應(yīng)該嗅探到一股惡臭味,怎么去修改,或許考慮使用狀態(tài)模式是一條途徑。

但狀態(tài)模式還有一點(diǎn)需要注意到,當(dāng)采用子類繼承實(shí)現(xiàn)多種具體狀態(tài)的時(shí)候,注意控制狀態(tài)的數(shù)量,以免出現(xiàn)子類數(shù)量膨脹的現(xiàn)象(在使用TypeScriptJava等更完整面向?qū)ο笳Z(yǔ)言時(shí))。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99129.html

相關(guān)文章

  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠?lái)都是中的主導(dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠?lái)都是JavaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語(yǔ)言,然而,近幾年,函數(shù)式編程越來(lái)越多得受到開(kāi)發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評(píng)論0 收藏0
  • 前端開(kāi)發(fā)中常的javascript設(shè)計(jì)模式

    摘要:代理模式,迭代器模式,單例模式,裝飾者模式最少知識(shí)原則一個(gè)軟件實(shí)體應(yīng)當(dāng)盡可能少地與其他實(shí)體發(fā)生相互作用。迭代器模式可以將迭代的過(guò)程從業(yè)務(wù)邏輯中分離出來(lái),在使用迭代器模式之后,即不用關(guān)心對(duì)象內(nèi)部構(gòu)造也可以按順序訪問(wèn)其中的每個(gè)元素。 接手項(xiàng)目越來(lái)越復(fù)雜的時(shí)候,有時(shí)寫(xiě)完一段代碼,總感覺(jué)代碼還有優(yōu)化的空間,卻不知道從何處去下手。設(shè)計(jì)模式主要目的是提升代碼可擴(kuò)展性以及可閱讀性。 本文主要以例子的...

    趙春朋 評(píng)論0 收藏0
  • 觀眾老爺們,來(lái)試試這個(gè) Vue 擼的數(shù)據(jù)可視化后臺(tái)吧

    摘要:至于如何優(yōu)雅地管理使用,再次祭出潘神的文章手摸手,帶你優(yōu)雅的使用掘金項(xiàng)目的后端接口文檔我是用的進(jìn)行的管理,其實(shí)有很多強(qiáng)大的功能,不僅僅是一個(gè)接口測(cè)試工具,接口文檔管理就是其中一個(gè)。 首先放個(gè)線上地址大家感受一下(由于后端用的是 leancloud 的免費(fèi)套餐,因此可能會(huì)比較慢): vue-data-board P.S. 建議大家盡量自己注冊(cè)一個(gè)賬號(hào)(可以隨便填一個(gè)密碼),如果用默認(rèn)的測(cè)...

    JinB 評(píng)論0 收藏0
  • 前端狀態(tài)管理請(qǐng)三思

    摘要:它們是單向數(shù)據(jù)流和狀態(tài)容器,而不是狀態(tài)管理。幾個(gè)月之前我開(kāi)始尋找可以解決狀態(tài)管理問(wèn)題的模式,最終我發(fā)現(xiàn)了狀態(tài)機(jī)的概念。狀態(tài)機(jī)不接受沒(méi)有明確定義的輸入作為當(dāng)前的狀態(tài)。狀態(tài)機(jī)強(qiáng)制開(kāi)發(fā)者以聲明式的方式思考。 最近我開(kāi)始思考React應(yīng)用的狀態(tài)管理。我已經(jīng)取得一些有趣的結(jié)論,并且在這篇文章里我會(huì)向你展示我們所謂的狀態(tài)管理并不是真的在管理狀態(tài)。 譯者:阿里云前端-也樹(shù) 原文鏈接:managing...

    魏憲會(huì) 評(píng)論0 收藏0
  • JS 狀態(tài)模式

    摘要:簡(jiǎn)介狀態(tài)模式允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變的時(shí)候改變它的行為,對(duì)象看起來(lái)似乎修改了它的類。狀態(tài)通常為一個(gè)或多個(gè)枚舉常量的表示。簡(jiǎn)而言之,當(dāng)遇到很多同級(jí)或者的時(shí)候,可以使用狀態(tài)模式來(lái)進(jìn)行簡(jiǎn)化。 1. 簡(jiǎn)介 狀態(tài)模式(State)允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變的時(shí)候改變它的行為,對(duì)象看起來(lái)似乎修改了它的類。其實(shí)就是用一個(gè)對(duì)象或者數(shù)組記錄一組狀態(tài),每個(gè)狀態(tài)對(duì)應(yīng)一個(gè)實(shí)現(xiàn),實(shí)現(xiàn)的時(shí)候根據(jù)狀態(tài)挨個(gè)去運(yùn)...

    xingqiba 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<