JSの状態モード

17163 ワード

level 01:電灯プログラム

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <script>
        var Light = function(){
            this.state = 'off'; //           off
            this.button = null; //       
        };
        Light.prototype.init = function(){
            var button = document.createElement( 'button' ),
                self = this;
            button.innerHTML = '  ';
            this.button = document.body.appendChild( button );
            this.button.onclick = function(){
                self.buttonWasPressed();
            }
        };
        Light.prototype.buttonWasPressed = function(){
            if ( this.state === 'off' ){
                console.log( '  ' );
                this.state = 'on';
            }else if ( this.state === 'on' ){
                console.log( '  ' );
                this.state = 'off';
            }
        };
        var light = new Light();
        light.init();
    script>
body>
html>
短所:
  • 明らかなbuttonWas Presed方法は開放の閉鎖原則に違反するので、毎回lightの状態を追加しますかます改正しますと、buttonWas Presed方法のコードを変更しなければなりません.これはbuttons Presedを非常に不安定な方法にしました.
  • 状態が多い場合には、ブットワンWas Presed方法が膨大になる可能性があります.
  • 状態間の切り替え関係は、単にbuttonWas Presed方法にif、else文を積み重ねていくだけであり、一つの状態を追加または修正するにはいくつかの操作を変更する必要があります.
  • level 02:状態モード改善電灯プログラム
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            // OffLightState:
            var OffLightState = function( light ){
                this.light = light;
            };
            OffLightState.prototype.buttonWasPressed = function(){
                console.log( '  ' ); // offLightState      
                this.light.setState( this.light.weakLightState ); //       weakLightState
            };
            // WeakLightState:
            var WeakLightState = function( light ){
                this.light = light;
            };
            WeakLightState.prototype.buttonWasPressed = function(){
                console.log( '  ' ); // weakLightState      
                this.light.setState( this.light.strongLightState ); //       strongLightState
            };
            // StrongLightState:
            var StrongLightState = function( light ){
                this.light = light;
            };
            StrongLightState.prototype.buttonWasPressed = function(){
                console.log( '  ' ); // strongLightState      
                this.light.setState( this.light.offLightState ); //       offLightState
            };
            var Light = function(){
                this.offLightState = new OffLightState( this );
                this.weakLightState = new WeakLightState( this );
                this.strongLightState = new StrongLightState( this );
                this.button = null;
            };
            Light.prototype.init = function(){
                var button = document.createElement( 'button' ),
                    self = this;
                this.button = document.body.appendChild( button );
                this.button.innerHTML = '  ';
                this.currState = this.offLightState; //       
                this.button.onclick = function(){
                    self.currState.buttonWasPressed();
                }
            };
            Light.prototype.setState = function( newState ){
                this.currState = newState;
            };
    
            var light = new Light();
            light.init();
        script>
    body>
    html>
    tips:前の電灯例では、状態モードプログラムの作成を完了しました.まずLightクラスを定義しました.Light類はここで文脈とも言われています.続いてLightのコンストラクタにおいて、各状態クラスのインスタンスオブジェクトを作成します.Contectはこれらの状態オブジェクトの参照を持って、状態オブジェクトに要求を委託します.
    各種のステータスクラスを作成したいです.lightオブジェクトは、ステータスクラスのコンストラクタに入力されます.ステータスオブジェクトもlightオブジェクトの参照を持って、light中のメソッドを呼び出したり、直接lightオブジェクトを操作したりする必要があります.
    var OffLightState = function( light ){
        this.light = light;
    };
    OffLightState.prototype.buttonWasPressed = function(){
        console.log( '  ' );
        this.light.setState( this.light.weakLightState );
    };
    状態モードの定義:
    オブジェクトが内部の状態を変更するときにその動作を変更することができます.オブジェクトはクラスを変更したように見えます.私たちはコンマで区切って、この文を二つの部分に分けて見ます.第一部では、状態を独立したクラスにカプセル化し、要求を現在の状態の対象に委託し、対象の内部状態が変化すると、異なる行動変化をもたらすという意味です.ランプの例はこの点を十分に説明しています.offとonという二つの異なる状態で同じボタンをクリックして、結果としての行動フィードバックは全く違っています.
    level 03:状態モード改善電灯プログラム
    残念なことに、JavaScriptは抽象類もインタフェースの概念もサポートしていません.状態モードを使う時は特に注意してください.状態のサブクラスを作成する時は、この状態にサブクラスをセットするためのブットエンドWas Presed方法を忘れてしまうと、状態が切り替わる時に異常を投げます.Contectはいつも状態の対象に依頼するbuttonWas Presed方法です.
    どんなに厳しくプログラマを要求しても、ミスを避けられないかもしれません.コンパイラの助けがなければ、プログラマの自覚と運のよさだけが頼りです.ここで提案した解決策は「テンプレート方法モード」と一致しています.抽象的な父類の抽象的な方法に直接に異常を投げさせます.この異常は少なくともプログラム実行中に発見されます.
    var State = function(){};
        State.prototype.buttonWasPressed = function(){
            throw new Error( '    buttonWasPressed        ' );
        };
        var SuperStrongLightState = function( light ){
            this.light = light;
        };
        SuperStrongLightState.prototype = new State(); //       
        SuperStrongLightState.prototype.buttonWasPressed = function(){ //    buttonWasPressed   
            console.log( '  ' );
            this.light.setState( this.light.offLightState );
        };
    状態モードのメリットとデメリット
    状態モードは状態と挙動の関係を定義し,それらを一つのクラスにカプセル化する.新しい状態クラスを追加することにより、新しい状態と変換が容易に増加します.Contextが無限に膨張しないように、状態切替の論理は状態種類に分布されています.また、Conteextの中の元々多すぎる条件分岐も取り除かれました.Contextにおける要求動作と状態クラスにおけるパッケージの動作は、独立して変化しやすく、互いに影響しない.
    状態モードにおける性能最適化点
    stateオブジェクトの作成と廃棄を管理する二つの選択があります.一つ目は、stateオブジェクトが必要とされた時だけ作成し、その後廃棄すること、もう一つは最初からすべての状態オブジェクトを作成し、いつまでも廃棄しないことです.もしstateオブジェクトが比較的大きいなら、最初の方法でメモリを節約できます.これにより、使われないオブジェクトを作成して、すぐにそれらを回収することができます.ただし、状態の変化が頻繁であれば、最初からこれらのstateオブジェクトを作成しても、廃棄する必要はありません.この章の例では、Contectオブジェクトごとにstateオブジェクトのセットを作成しましたが、実際にはこれらのstateオブジェクトの間で共有できます.各Contectオブジェクトは一つのstateオブジェクトを共有できます.これも享元モードの応用シーンの一つです.ステータスモードとポリシーモードの関係
    状態モードと戦略モードは、双子のように、アルゴリズムまたは挙動の一連をカプセル化しています.それらの類図はほぼ同じに見えるが、意図的には大きく違っています.
    ポリシーモードとステータスモードの同じ点は、いずれもコンテキスト、いくつかのポリシーまたはステータスクラスがあり、コンテキストはこれらのクラスに依頼して実行される.
    これらの違いはポリシーモードのそれぞれのポリシークラスの間には平等で平行であり、それらの間には何の連絡もないので、お客様はこれらのポリシークラスの役割を熟知していなければなりません.状態モードでは、状態と状態に対応する行為はすでにカプセル化されており、状態間の切り替えも早く規定されており、「行動を変える」ということは状態モード内で発生している.お客様にとって、これらの詳細を知る必要はありません.これはまさに状態モードの役割です.
    level 02:JavaScriptバージョンのステータスマシン
    状態モードは状態マシンの実現の一つですが、JavaScriptという「類なし」言語では、状態オブジェクトをクラスから作成するように規定されていません.もう一つのポイントは、JavaScriptは委託技術を非常に便利に使用することができ、事前に一つのオブジェクトに別のオブジェクトを持たせる必要はない.以下の状態マシンは、Funtions.prototype.call方法で直接に依頼をある字面量のオブジェクトに依頼して実行します.
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            var Light = function(){
                this.button = null;
            };
            Light.prototype.init = function(){
                var button = document.createElement( 'button' ),
                    self = this;
                button.innerHTML = '   ';
                this.currState = FSM.off; //       
                this.button = document.body.appendChild( button );
                this.button.onclick = function(){
                    self.currState.buttonWasPressed.call( self ); //        FSM    
                }
            };
            var FSM = {
                off: {
                    buttonWasPressed: function(){
                        console.log( '  ' );
                        this.button.innerHTML = '        ';
                        this.currState = FSM.on;
                    }
                },
                on: {
                    buttonWasPressed: function(){
                        console.log( '  ' );
                        this.button.innerHTML = '        ';
                        this.currState = FSM.off;
                    }
                }
            };
            var light = new Light();
            light.init();
        script>
    body>
    
    html>
    転載先:http://www.cnblogs.com/tracyzeng/p/8484198.html