在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 設計模式之狀態(tài)模式
代碼復用模式(避免篇)
S.O.L.I.D 五大原則之接口隔離原則 ISP
設計模式之狀態(tài)模式
JavaScript 核心(晉級高手必讀篇)
設計模式之建造者模式
JavaScript 與 DOM(上)——也適用于新手
設計模式之中介者模式
設計模式之裝飾者模式
設計模式之模板方法
設計模式之外觀模式
強大的原型和原型鏈
設計模式之構造函數模式
揭秘命名函數表達式
深入理解J avaScript 系列(結局篇)
執(zhí)行上下文(Execution Contexts)
函數(Functions)
《你真懂 JavaScript 嗎?》答案詳解
設計模式之適配器模式
設計模式之組合模式
設計模式之命令模式
S.O.L.I.D 五大原則之單一職責 SRP
編寫高質量 JavaScript 代碼的基本要點
求值策略
閉包(Closures)
對象創(chuàng)建模式(上篇)
This? Yes,this!
設計模式之代理模式
變量對象(Variable Object)
S.O.L.I.D 五大原則之里氏替換原則 LSP
面向對象編程之一般理論
設計模式之單例模式
Function 模式(上篇)
S.O.L.I.D 五大原則之依賴倒置原則 DIP
設計模式之迭代器模式
立即調用的函數表達式
設計模式之享元模式
設計模式之原型模式
根本沒有“JSON 對象”這回事!
JavaScript 與 DOM(下)
面向對象編程之 ECMAScript 實現
全面解析 Module 模式
對象創(chuàng)建模式(下篇)
設計模式之職責鏈模式
S.O.L.I.D 五大原則之開閉原則 OCP
設計模式之橋接模式
設計模式之策略模式
設計模式之觀察者模式
代碼復用模式(推薦篇)
作用域鏈(Scope Chain)
Function 模式(下篇)
設計模式之工廠模式

設計模式之狀態(tài)模式

介紹

狀態(tài)模式(State)允許一個對象在其內部狀態(tài)改變的時候改變它的行為,對象看起來似乎修改了它的類。

正文

舉個例子,就比如我們平時在下載東西,通常就會有好幾個狀態(tài),比如準備狀態(tài)(ReadyState)、下載狀態(tài)(DownloadingState)、暫停狀態(tài)(DownloadPausedState)、下載完畢狀態(tài)(DownloadedState)、失敗狀態(tài)(DownloadFailedState),也就是說在每個狀態(tài)都只可以做當前狀態(tài)才可以做的事情,而不能做其它狀態(tài)能做的事兒。

由于 State 模式描述了下載(Download)如何在每一種狀態(tài)下表現出不同的行為。這一模式的關鍵思想就是引入了一個叫做 State 的抽象類(或 JS 里的函數)來表示下載狀態(tài),State 函數(作為原型)為每個狀態(tài)的子類(繼承函數)聲明了一些公共接口。其每個繼承函數實現與特定狀態(tài)相關的行為,比如 DownloadingState 和 DownloadedState 分別實現了正在下載和下載完畢的行為。這些行為可以通過 Download 來來維護。

讓我們來實現一把,首先定義作為其他基礎函數的原型的 State 函數:

var State = function () {
};
State.prototype.download = function () {
    throw new Error("該方法必須被重載!");
};
State.prototype.pause = function () {
    throw new Error("該方法必須被重載!");
};
State.prototype.fail = function () {
    throw new Error("該方法必須被重載!");
};
State.prototype.finish = function () {
    throw new Error("該方法必須被重載!");
};

我們?yōu)?State 的原型定義了 4 個方法接口,分別對應著下載(download)、暫停(pause)、失?。╢ail)、結束(finish)以便子函數可以重寫。

在編寫子函數之前,我們先來編寫一個 ReadyState 函數,以便可以將狀態(tài)傳遞給第一個 download 狀態(tài):

var ReadyState = function (oDownload) {
    State.apply(this);
    this.oDownload = oDownload;
};
ReadyState.prototype = new State();
ReadyState.prototype.download = function () {
    this.oDownload.setState(this.oDownload.getDownloadingState());
    // Ready以后,可以開始下載,所以設置了Download函數里的狀態(tài)獲取方法
 console.log("Start Download!");
};
ReadyState.prototype.pause = function () {
    throw new Error("還沒開始下載,不能暫停!");
};
ReadyState.prototype.fail = function () {
    throw new Error("文件還沒開始下載,怎么能說失敗呢!");
};
ReadyState.prototype.finish = function () {
    throw new Error("文件還沒開始下載,當然也不能結束了!");
};

該函數接收了一個 Download 維護函數的實例作為參數,Download 函數用于控制狀態(tài)的改變和獲?。愃朴谥醒肟刂破?,讓外部調用),ReadyState 重寫了原型的 download 方法,以便開始進行下載。我們繼續(xù)來看 Download 函數的主要功能:

var Download = function () {
    this.oState = new ReadyState(this);
};
Download.prototype.setState = function (oState) {
    this.oState = oState;
};
// 對外暴露的四個公共方法,以便外部調用
Download.prototype.download = function () {
    this.oState.download();
};
Download.prototype.pause = function () {
    this.oState.pause();
};
Download.prototype.fail = function () {
    this.oState.fail();
};
Download.prototype.finish = function () {
    this.oState.finish();
};
//獲取各種狀態(tài),傳入當前this對象
Download.prototype.getReadyState = function () {
    return new ReadyState(this);
};
Download.prototype.getDownloadingState = function () {
    return new DownloadingState(this);
};
Download.prototype.getDownloadPausedState = function () {
    return new DownloadPausedState(this);
};
Download.prototype.getDownloadedState = function () {
    return new DownloadedState(this);
};
Download.prototype.getDownloadedFailedState = function () {
    return new DownloadFailedState(this);
};

Download 函數的原型提供了 8 個方法,4 個是對用于下載狀態(tài)的操作行為,另外 4 個是用于獲取當前四個不同的狀態(tài),這 4 個方法都接收 this 作為參數,也就是將 Download 實例自身作為一個參數傳遞給處理該請求的狀態(tài)對象(ReadyState 以及后面要實現的繼承函數),這使得狀態(tài)對象比必要的時候可以訪問 oDownlaod。

接下來,繼續(xù)定義 4 個相關狀態(tài)的函數:

var DownloadingState = function (oDownload) {
    State.apply(this);
    this.oDownload = oDownload;
};
DownloadingState.prototype = new State();
DownloadingState.prototype.download = function () {
    throw new Error("文件已經正在下載中了!");
};
DownloadingState.prototype.pause = function () { this.oDownload.setState(this.oDownload.getDownloadPausedState());
    console.log("暫停下載!");
};
DownloadingState.prototype.fail = function () { this.oDownload.setState(this.oDownload.getDownloadedFailedState());
    console.log("下載失敗!");
};
DownloadingState.prototype.finish = function () {
    this.oDownload.setState(this.oDownload.getDownloadedState());
    console.log("下載完畢!");
};

DownloadingState 的主要注意事項就是已經正在下載的文件,不能再次開始下載了,其它的狀態(tài)都可以連續(xù)進行。

var DownloadPausedState = function (oDownload) {
    State.apply(this);
    this.oDownload = oDownload;
};
DownloadPausedState.prototype = new State();
DownloadPausedState.prototype.download = function () {
    this.oDownload.setState(this.oDownload.getDownloadingState());
    console.log("繼續(xù)下載!");
};
DownloadPausedState.prototype.pause = function () {
    throw new Error("已經暫停了,咋還要暫停呢!");
};
DownloadPausedState.prototype.fail = function () { this.oDownload.setState(this.oDownload.getDownloadedFailedState());
    console.log("下載失敗!");
};
DownloadPausedState.prototype.finish = function () {
    this.oDownload.setState(this.oDownload.getDownloadedState());
    console.log("下載完畢!");
};
DownloadPausedState函數里要注意的是,已經暫停的下載,不能再次暫停。
var DownloadedState = function (oDownload) {
    State.apply(this);
    this.oDownload = oDownload;
};
DownloadedState.prototype = new State();
DownloadedState.prototype.download = function () {
    this.oDownload.setState(this.oDownload.getDownloadingState());
    console.log("重新下載!");
};
DownloadedState.prototype.pause = function () {
    throw new Error("對下載完了,還暫停啥?");
};
DownloadedState.prototype.fail = function () {
    throw new Error("都下載成功了,咋會失敗呢?");
};
DownloadedState.prototype.finish = function () {
    throw new Error("下載成功了,不能再為成功了吧!");
};

DownloadedState 函數,同理成功下載以后,不能再設置 finish 了,只能設置重新下載狀態(tài)。

var DownloadFailedState = function (oDownload) {
    State.apply(this);
    this.oDownload = oDownload;
};
DownloadFailedState.prototype = new State();
DownloadFailedState.prototype.download = function () {
    this.oDownload.setState(this.oDownload.getDownloadingState());
    console.log("嘗試重新下載!");
};
DownloadFailedState.prototype.pause = function () {
    throw new Error("失敗的下載,也不能暫停!");
};
DownloadFailedState.prototype.fail = function () {
    throw new Error("都失敗了,咋還失敗呢!");
};
DownloadFailedState.prototype.finish = function () {
    throw new Error("失敗的下載,肯定也不會成功!");
};

同理,DownloadFailedState 函數的失敗狀態(tài),也不能再次失敗,但可以和 finished 以后再次嘗試重新下載。

調用測試代碼,就非常簡單了,我們在 HTML 里演示吧,首先是要了 jquery,然后有 3 個按鈕分別代表:開始下載、暫停、重新下載。(注意在 Firefox 里用 firebug 查看結果,因為用了 console.log 方法)。

<html>
<head>
    <link type="text/css" rel="stylesheet"  />
    <title>State Pattern</title>
    <script type="text/javascript" src="/jquery.js"></script>
    <script type="text/javascript" src="Download.js"></script>
    <script type="text/javascript" src="states/State.js"></script>
    <script type="text/javascript" src="states/DownloadFailedState.js"></script>
    <script type="text/javascript" src="states/DownloadPausedState.js"></script>
    <script type="text/javascript" src="states/DownloadedState.js"></script>
    <script type="text/javascript" src="states/DownloadingState.js"></script>
    <script type="text/javascript" src="states/ReadyState.js"></script>
</head>
<body>
    <input type="button" value="開始下載" id="download_button" />
    <input type="button" value="暫停" id="pause_button" />
    <input type="button" value="重新下載" id="resume_button" />
    <script type="text/javascript">
        var oDownload = new Download();
        $("#download_button").click(function () {
            oDownload.download();
        });
        $("#pause_button").click(function () {
            oDownload.pause();
        });
        $("#resume_button").click(function () {
            oDownload.download();
        });
    </script>
</body>
</html>

總結

狀態(tài)模式的使用場景也特別明確,有如下兩點:

  1. 一個對象的行為取決于它的狀態(tài),并且它必須在運行時刻根據狀態(tài)改變它的行為。
  2. 一個操作中含有大量的分支語句,而且這些分支語句依賴于該對象的狀態(tài)。狀態(tài)通常為一個或多個枚舉常量的表示。