JavaScriptデザインモードシリーズ-ポリシーモードとダイナミックフォームの検証


ストラテジスト・モードは、一連のアルゴリズムを定義し、それらを一つずつカプセル化し、互いに置き換えることができるようにする政策モデルとも呼ばれる.パッケージのポリシーアルゴリズムは一般的に独立しており、ポリシーモードは入力に応じてどのアルゴリズムを採用するかを調整する.肝心な点は戦略の実現と使用の分離です.
注意:本論文ではIIIIIIIFreediately Invoked Function Expressionなどの符号化技法が用いられます.ES 6の文法let/const、矢印関数、restパラメータ、短絡演算子などは、まだ接触していない場合はリンクをクリックして勉強します.
1.あなたが見た戦略モデル
今は電子製品の種類が多くて、サイズも多様です.たまには、中を開けてみたいです.でも、ねじの規格が多くて、ドライバーのサイズも多いです.もし規格があると、螺子の刃を一つ買いたいです.家にはドライバーが積まれています.だから、今はみんな多機能のドライバーセットを使っています.ドライバーは一つだけ必要です.いろいろな規格のねじを触ると、ドライバーを交換すればいいです.便利です.体積も小さくなります.
また栗を挙げます.一台の車のタイヤはいろいろな規格があります.ぬかるみの道が多い時は泥のタイヤを使ってもいいです.雪の中は雪のタイヤをたくさん使ってもいいです.高速道路が多い時は高性能のタイヤを使って、使う場面によって違うタイヤを交換すればいいです.車全体を交換する必要はありません.
これらは戦略モードの例であり、ドライバー/車はパッケージの文脈に属しており、パッケージとは異なるドライバー/タイヤを使用しており、ドライバー/タイヤはここで戦略に相当し、必要に応じて異なる使用戦略を交換することができる.
これらのシーンには、以下のような特徴があります.
  • ドライバーとタイヤの間は独立していますが、互いに交換できます.
  • ドライバー/車(パッケージコンテキスト)は、必要に応じて異なるポリシーを選択できます.
  • 2.インスタンスのコード実装
    具体的な例をプログラム上の例で実証し,定量化しやすい.
    場面はこのようにして、ある電気商のウェブサイトは一つのイベントを開催したいです.セールを通じて在庫品を販売します.ある商品は100%から30%を減らします.ある商品は200%を超えて80%を減らします.ある商品は直接8割で販売します.このようなロジックは私達に任せて、どうやって実現しますか?
    function priceCalculate(discountType, price) {
        if (discountType === 'minus100_30') {           //  100 30
            return price - Math.floor(price / 100) * 30
        }
        else if (discountType === 'minus200_80') {  //  200 80
            return price - Math.floor(price / 200) * 80
        }
        else if (discountType === 'percent80') {    // 8 
            return price * 0.8
        }
    }
    
    priceCalculate('minus100_30', 270)    //   : 210
    priceCalculate('percent80', 250)      //   : 200
    入力した割引の種類を判断して商品の総価格を計算する方式で、いくつかのif-elseが需要を満たしていますが、このようなやり方の欠点も明らかです.
  • priceCalculate関数は、割引の種類が増えるにつれて、文がますます肥大化すると判断した.
  • 新しい割引タイプまたは割引タイプのアルゴリズムが変更された場合、if-else関数の実装を変更する必要があります.
  • の多重化可能性の差は、他のところにも同様のアルゴリズムがあるが、規則が違って、上記のコードは多重化できない.
  • 割引を計算するアルゴリズムの部分を抽出して一つの対象として保存します.割引のタイプはkeyとして保存します.このようにインデックスを作成する時は対象のキーインデックスを通じて具体的なアルゴリズムを呼び出します.
    const DiscountMap = {
        minus100_30: function(price) {
            return price - Math.floor(price / 100) * 30
        },
        minus200_80: function(price) {
            return price - Math.floor(price / 200) * 80
        },
        percent80: function(price) {
            return price * 0.8
        }
    }
    
    /*      */
    function priceCalculate(discountType, price) {
        return DiscountMap[discountType] && DiscountMap[discountType](price)
    }
    
    priceCalculate('minus100_30', 270)
    priceCalculate('percent80', 250)
    
    //   : 210
    //   : 200
    このようにアルゴリズムの実現とアルゴリズムの使用は分離され、新しいアルゴリズムを追加するのも非常に簡単になります.
    DiscountMap.minus150_40 = function(price) {
        return price - Math.floor(price / 150) * 40
    }
    計算アルゴリズムが隠れていることを望むなら、IIIFを介してクローズド方式を使用することができます.この場合、追加策の入口を追加して、拡張を容易にする必要があります.
    const PriceCalculate = (function() {
        /*        */
        const DiscountMap = {
            minus100_30: function(price) {      //  100 30
                return price - Math.floor(price / 100) * 30
            },
            minus200_80: function(price) {      //  200 80
                return price - Math.floor(price / 200) * 80
            },
            percent80: function(price) {        // 8 
                return price * 0.8
            }
        }
        
        return {
            priceClac: function(discountType, price) {
                return DiscountMap[discountType] && DiscountMap[discountType](price)
            },
            addStrategy: function(discountType, fn) {        //        
                if (DiscountMap[discountType]) return
                DiscountMap[discountType] = fn
            }
        }
    })()
    
    PriceCalculate.priceClac('minus100_30', 270)    //   : 210
    
    PriceCalculate.addStrategy('minus150_40', function(price) {
        return price - Math.floor(price / 150) * 40
    })
    PriceCalculate.priceClac('minus150_40', 270)    //   : 230
    このようにアルゴリズムは隠れており,拡張のために戦略の入口を増やすために予約されている.
    3.戦略モードの共通実現
    上記の例に従って、ポリシーモードを抽出し、割引計算方法は、ポリシー(Strategy)と見なされ、これらのポリシーの間で相互に置換され、具体的な割引の計算プロセスは、パッケージコンテキスト(Contect)と見なされ、パッケージコンテキストは、必要に応じて異なるポリシーを選択することができる.
    主に次のいくつかの概念があります.
  • Contect:パッケージコンテキストは、必要に応じてポリシーを呼び出し、ポリシーに対する外部からの直接的な呼び出しを遮断し、外部に一つのインターフェースを提供し、必要に応じて対応するポリシーを呼び出す.
  • Strategy:戦略は、具体的なアルゴリズムを含み、その方法の外観は同じであるため、互いに代替することができる.
  • StrategyMap:パッケージコンテキスト起動のためのすべてのポリシーの統合.
  • 構造図は以下の通りです
    以下は汎用化の方法で実現してみます.
    const StrategyMap = {}
    
    function context(type, ...rest) {
        return StrategyMap[type] && StrategyMap[type](...rest)
    }
    
    StrategyMap.minus100_30 = function(price) { 
          return price - Math.floor(price / 100) * 30
    }
    
    context('minus100_30', 270)            //   : 210
    汎用実現は比較的簡単に見えるようですが、ここでプロジェクトの実戦を共有します.
    4.実戦での戦略モード
    4.1表formater
    ここではVue+ElementUIプロジェクトで使われている例を挙げます.他のフレームのプロジェクト原理も似ています.皆さんと共有してください.
    ElementのテーブルコントロールのColumnは、コンテンツをフォーマットするためのpriceCalculateパラメータを受け取り、その種類は関数であり、いくつかの特定のパラメータも受け入れることができます.
    ファイルサイズを例にとると、バックエンドは常にビット単位のファイルサイズを直接転送します.フロントエンドはバックエンドのデータによって必要で、必要に応じて自分の必要な単位のファイルサイズに変換します.
    まずファイル計算のアルゴリズムを実行します.
    export const StrategyMap = {
        /* Strategy 1:      (bit)    KB */
        bitToKB: val => {
            const num = Number(val)
            return isNaN(num) ? val : (num / 1024).toFixed(0) + 'KB'
        },
        /* Strategy 2:      (bit)    MB */
        bitToMB: val => {
            const num = Number(val)
            return isNaN(num) ? val : (num / 1024 / 1024).toFixed(1) + 'MB'
        }
    }
    
    /* Context:   el   formatter */
    const strategyContext = function(type, rowKey){ 
      return function(row, column, cellValue, index){
          StrategyMap[type](row[rowKey])
      }
    }
    
    export default strategyContext
    コンポーネントの中で直接できます.
    
    
    
        import strategyContext from './strategyContext.js'
        
        export default {
            name: 'ElTableDemo',
            data() {
                return {
                    strategyContext,
                    tableData: [
                        { date: '2019-05-02', name: '  1', sizeKb: 1234, sizeMb: 1234426 },
                        { date: '2019-05-04', name: '  2', sizeKb: 4213, sizeMb: 8636152 }]
                }
            }
        }