目次
ストラテジーモードとは何ですか?
ホームページ ウェブフロントエンド jsチュートリアル デザインパターンの戦略パターンをフロントエンドで使用する方法

デザインパターンの戦略パターンをフロントエンドで使用する方法

May 24, 2018 am 09:50 AM
フロントエンド どうやって デザインパターン

今回はデザインパターン戦略パターンをフロントエンドで使用する方法と、デザインパターンの戦略パターンをフロントエンドで使用する際の注意点についてお届けします。実際のケースを見てみましょう。

ストラテジーモードとは何ですか?

GoF 4 兄弟による古典的な「デザイン パターン」では、戦略パターンは次のように定義されています。

一連のアルゴリズムを定義し、それらを 1 つずつカプセル化して、互換性を持たせる。

上記の文は文字通り非常に単純です。しかし、開発プロセスにそれをどのように適用するかは、定義が 1 つだけではまだわかりにくいです。著者がかつて取り組んだ小売業者の購買、販売、在庫システムを例に挙げます。

あるスーパーマーケットでは、調査と分析の後、いくつかのプロモーション戦略を策定しました。
  1. は 10 割引です。 100以上の購入

  2. 200以上の購入で30割引

  3. 300以上の購入で50割引

  4. 。 。 。

レジソフトのインターフェースはこんな感じです(簡単な図):

デザインパターンの戦略パターンをフロントエンドで使用する方法

実際の消費額はどのように計算すればよいでしょうか?

最初の実装は次のとおりです:

//方便起见,我们把各个促销策略定义为枚举值:0,1,2...
var getActualTotal = function(onSaleType,originTotal){
    if(onSaleType===0){
        return originTotal-Math.floor(originTotal/100)*10
    }
    if(onSaleType===1){
        return originTotal-Math.floor(originTotal/200)*30
    }
    if(onSaleType===0){
        return originTotal-Math.floor(originTotal/300)*50
    }
}
getActualTotal(1,2680); //2208
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

上記のコードは非常に単純ですが、その欠点も明らかです。私の完全削減戦略が徐々に増加するにつれて、getActualTotal 関数はますます大きくなり、if の判断が満載になります。注意しないと間違いを犯しやすくなります。 。 getActualTotal函数会越变越大,而且充满了if判断,稍一疏忽就容易弄错。

OK,有人说我很懒,虽然这样不够优雅但并不影响我的使用,毕竟满减策略再多也多不到哪去。
我只能说,需求永远不是程序员定的。。这时,市场人员说我们新版程序添加了会员功能,我们需要支持以下的促销策略:

会员促销策略:
  1. 会员充300返60,且首单打9折

  2. 会员充500返100,且首单打8折

  3. 会员充1000返300,且首单打7折

  4. ...

这个时候,如果你还在原先的getActualTotal函数中继续添加if判断,我想如果你的领导review你这段代码,可能会怀疑自己当初怎么把你招进来。。

OK,我们终于下定决心要重构促销策略的代码,我们可以这么做:

var vipPolicy_0=function(originTotal){
    return originTotal-Math.floor(originTotal/100)*10
}
var vipPolicy_1=function(originTotal){
    return originTotal-Math.floor(originTotal/200)*30
}
...
//会员充1000返300
var vipPolicy_10=function(account,originTotal){
    if(account===0){
        account+=1300;
        return originTotal*0.9
    }else{
        account+=1300;
        return originTotal;
    }
    return originTotal-Math.floor(originTotal/200)*30
}
...
var vipPolicy_n=function(){
    ...
}
var getActualTotal=function(onSaleType,originTotal,account){
    switch(onSaleType){
        case 0:
            return vipPolicy_0(originTotal);
        case 1:
            return vipPolicy_0(originTotal);
        ...
        case n:
            return ...
        default:
            return originTotal;
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

好了,现在我们每种策略都有自己独立的空间了,看起来井井有条。但是还有两个问题没有解决:

  1. 随着促销策略的增加,getActualTotal的代码量依然会越来越大

  2. 系统缺乏弹性,如果需要增加一种策略,那么除了添加一个策略函数,还需要修改switch...case..语句

让我们再来回顾一下策略模式的定义:

定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换

在我们的例子中,每种促销策略的实现方式是不一样的,但我们最终的目的都是为了求得实际金额。策略模式可以把我们对促销策略的算法一个个封装起来,并且使它们可互相替换而不影响我们对实际金额的求值,这正好是我们所需要的。

下面我们用策略模式来重构上面的代码:

var policies={
    "Type_0":function(originTotal){
        return originTotal-Math.floor(originTotal/100)*10 
    },
    "Type_1":function(originTotal){
        return originTotal-Math.floor(originTotal/200)*30 
    },
    ...
    "Type_n":function(originTotal){
        ... 
    }
}
var getActualTotal=function(onSaleType,originTotal,account){
    return policies["Type_"+onSaleType](originTotal,account)
}
//执行
getActualTotal(0,2680.00);//2208
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

分析上面的代码我们发现,不管促销策略如何增加,getActualTotal函数完全不需要再变化了。我们要做的,就是增加新策略的函数而已。

通过策略模式的代码,我们消除了让人反胃的大片条件分支语句,getActualTotal

OK、これは十分に洗練されていないと言う人もいますが、結局のところ、完全な削減戦略をどれだけ使用しても十分ではありません。
言えることは、要件は決してプログラマーによって決定されるものではないということです。 。現時点では、市場スタッフは、プログラムの新しいバージョンにはメンバーシップ機能が追加されており、次のプロモーション戦略をサポートする必要があると述べました:

メンバープロモーション戦略:
  1. メンバーに 300 をチャージすると 60 が戻ってくる、そして最初の注文で 10% オフ🎜🎜🎜🎜メンバーは 500 100 をチャージすると、初回注文で 20% オフになります🎜🎜🎜🎜 メンバーとして 1000 をチャージすると、300 がバックされ、さ​​らに初回注文では 30% オフになります🎜🎜🎜 🎜...🎜🎜🎜🎜この時点で、まだ元の getActualTotal を使用している場合は、引き続き if 判定を関数に追加してください。リーダーがレビューしてくれると思います。コード、彼はそもそもなぜあなたを雇ったのか疑問に思うかもしれません。 。 🎜🎜OK、ついにプロモーション戦略のコードをリファクタリングすることにしました。これを行うことができます: 🎜
    //方便起见,我们把各个促销策略定义为枚举值:0,1,2...
    var getActualTotal = function(onSaleType,originTotal){
        if(onSaleType===0){
            return originTotal-Math.floor(originTotal/100)*10
        }
        if(onSaleType===1){
            return originTotal-Math.floor(originTotal/200)*30
        }
        if(onSaleType===0){
            return originTotal-Math.floor(originTotal/300)*50
        }
    }
    getActualTotal(1,2680); //2208
    ログイン後にコピー
    ログイン後にコピー
    ログイン後にコピー
    🎜 さて、各戦略には独自の独立したスペースがあり、よく整理されているように見えます。しかし、まだ解決されていない問題が 2 つあります: 🎜🎜🎜🎜 プロモーション戦略の増加に伴い、getActualTotal のコード量は依然として増大するでしょう 🎜🎜🎜🎜 システムは柔軟性に欠けています。戦略を追加する必要がある場合は、戦略関数の追加に加えて、switch...case.. ステートメントも変更する必要があります🎜🎜🎜🎜戦略の定義を確認してみましょうパターン: 🎜🎜一連のアルゴリズムを定義します。これらは 1 つずつカプセル化され、交換可能になります。この例では、各プロモーション戦略の実装は異なりますが、最終的な目標は実際の量を見つけることです。戦略パターンは、プロモーション戦略のアルゴリズムを 1 つずつカプセル化し、実際の金額の評価に影響を与えることなく互換性を持たせることができます。これはまさに私たちが必要としているものです。 🎜🎜 戦略パターンを使用して上記のコードを再構築しましょう: 🎜
    var vipPolicy_0=function(originTotal){
        return originTotal-Math.floor(originTotal/100)*10
    }
    var vipPolicy_1=function(originTotal){
        return originTotal-Math.floor(originTotal/200)*30
    }
    ...
    //会员充1000返300
    var vipPolicy_10=function(account,originTotal){
        if(account===0){
            account+=1300;
            return originTotal*0.9
        }else{
            account+=1300;
            return originTotal;
        }
        return originTotal-Math.floor(originTotal/200)*30
    }
    ...
    var vipPolicy_n=function(){
        ...
    }
    var getActualTotal=function(onSaleType,originTotal,account){
        switch(onSaleType){
            case 0:
                return vipPolicy_0(originTotal);
            case 1:
                return vipPolicy_0(originTotal);
            ...
            case n:
                return ...
            default:
                return originTotal;
        }
    }
    ログイン後にコピー
    ログイン後にコピー
    ログイン後にコピー
    🎜 上記のコードを分析すると、プロモーション戦略がどのように増加しても、getActualTotal 関数はまったく変更する必要がないことがわかりました。 。新しい戦略の機能を追加するだけです。 🎜🎜 ストラテジ パターン コードを通じて、胃が痛むような条件分岐ステートメントを排除します。getActualTotal 自体には計算能力はありませんが、計算をストラテジ関数に委任します。 🎜🎜これから、戦略パターン実装の重要なポイントを要約できます: 🎜🎜🎜🎜変化するアルゴリズムを独立した戦略関数にカプセル化し、特定の計算を担当します🎜
  2. 顧客のリクエストを受け付け、そのリクエストを特定の戦略関数に委任する

UML図で表すと以下のようになります。上の写真を見て、はっきりと理解できましたか?それなら急いでストラテジーモードに挑戦してください!
デザインパターンの戦略パターンをフロントエンドで使用する方法

参考書籍:


『デザインパターン:再利用可能
    オブジェクト指向
  1. ソフトウェアの基礎』

    『Dahuaデザインパターン』
  2. デザインパターンと開発実践》
  3. 私は数年フロントエンド開発をしていますが、デザインパターンを深く勉強してまとめたことがありませんでした。建築関連の仕事をすることが多くなるにつれ、デザインパターンが自分の進むべき道において障害になっていると感じることが増えてきました。したがって、今日から古典的なデザイン パターンといくつかの主要なオブジェクト指向原則を深く研究し、要約することから始めましょう。

    初日の今日は、まずストラテジーモードについて話しましょう。
ストラテジーモードとは何ですか?
GoF 4 兄弟による古典的な「デザイン パターン」では、戦略パターンは次のように定義されています。

一連のアルゴリズムを定義し、それらを 1 つずつカプセル化して、互換性を持たせる。

上記の文は文字通り非常に単純です。しかし、開発プロセスにそれをどのように適用するかは、定義が 1 つだけではまだわかりにくいです。著者がかつて取り組んだ小売業者の購買、販売、在庫システムを例に挙げます。

あるスーパーマーケットでは、調査と分析の後、いくつかのプロモーション戦略を策定しました。

は 10 割引です。 100以上の購入
  1. 200以上の購入で30割引

  2. 300以上の購入で50割引

  3. 。 。 。

  4. レジソフトのインターフェースはこんな感じです(簡単な図):

実際の消費額はどのように計算すればよいでしょうか?

最初の実装は次のとおりです: デザインパターンの戦略パターンをフロントエンドで使用する方法

//方便起见,我们把各个促销策略定义为枚举值:0,1,2...
var getActualTotal = function(onSaleType,originTotal){
    if(onSaleType===0){
        return originTotal-Math.floor(originTotal/100)*10
    }
    if(onSaleType===1){
        return originTotal-Math.floor(originTotal/200)*30
    }
    if(onSaleType===0){
        return originTotal-Math.floor(originTotal/300)*50
    }
}
getActualTotal(1,2680); //2208
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
上記のコードは非常に単純ですが、その欠点も明らかです。私の完全削減戦略が徐々に増加するにつれて、getActualTotal 関数はますます大きくなり、if の判断が満載になります。注意しないと間違いを犯しやすくなります。 。

OK、これは十分に洗練されていないと言う人もいますが、結局のところ、完全な削減戦略をどれだけ使用しても十分ではありません。

要件は決してプログラマによって決定されるものではないとしか言​​えません。 。現時点では、市場スタッフは、プログラムの新しいバージョンにはメンバーシップ機能が追加されており、次のプロモーション戦略をサポートする必要があると述べました:

メンバープロモーション戦略: getActualTotal函数会越变越大,而且充满了if判断,稍一疏忽就容易弄错。

OK,有人说我很懒,虽然这样不够优雅但并不影响我的使用,毕竟满减策略再多也多不到哪去。
我只能说,需求永远不是程序员定的。。这时,市场人员说我们新版程序添加了会员功能,我们需要支持以下的促销策略:

会员促销策略:
  1. 会员充300返60,且首单打9折

  2. 会员充500返100,且首单打8折

  3. 会员充1000返300,且首单打7折

  4. ...

这个时候,如果你还在原先的getActualTotal函数中继续添加if判断,我想如果你的领导review你这段代码,可能会怀疑自己当初怎么把你招进来。。

OK,我们终于下定决心要重构促销策略的代码,我们可以这么做:

var vipPolicy_0=function(originTotal){
    return originTotal-Math.floor(originTotal/100)*10
}
var vipPolicy_1=function(originTotal){
    return originTotal-Math.floor(originTotal/200)*30
}
...
//会员充1000返300
var vipPolicy_10=function(account,originTotal){
    if(account===0){
        account+=1300;
        return originTotal*0.9
    }else{
        account+=1300;
        return originTotal;
    }
    return originTotal-Math.floor(originTotal/200)*30
}
...
var vipPolicy_n=function(){
    ...
}
var getActualTotal=function(onSaleType,originTotal,account){
    switch(onSaleType){
        case 0:
            return vipPolicy_0(originTotal);
        case 1:
            return vipPolicy_0(originTotal);
        ...
        case n:
            return ...
        default:
            return originTotal;
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

好了,现在我们每种策略都有自己独立的空间了,看起来井井有条。但是还有两个问题没有解决:

  1. 随着促销策略的增加,getActualTotal的代码量依然会越来越大

  2. 系统缺乏弹性,如果需要增加一种策略,那么除了添加一个策略函数,还需要修改switch...case..

メンバーに 300 をチャージすると 60 が戻ってくる、そして最初の注文で 10% オフ

🎜🎜メンバーは 500 100 をチャージすると、初回注文で 20% オフになります🎜🎜🎜🎜 メンバーとして 1000 をチャージすると、300 がバックされ、さ​​らに初回注文では 30% オフになります🎜🎜🎜 🎜...🎜🎜🎜🎜この時点で、まだ元の getActualTotal を使用している場合は、引き続き if 判定を関数に追加してください。リーダーがレビューしてくれると思います。コード、彼はそもそもなぜあなたを雇ったのか疑問に思うかもしれません。 。 🎜🎜OK、ついにプロモーション戦略のコードをリファクタリングすることにしました。これを行うことができます: 🎜
var policies={
    "Type_0":function(originTotal){
        return originTotal-Math.floor(originTotal/100)*10 
    },
    "Type_1":function(originTotal){
        return originTotal-Math.floor(originTotal/200)*30 
    },
    ...
    "Type_n":function(originTotal){
        ... 
    }
}
var getActualTotal=function(onSaleType,originTotal,account){
    return policies["Type_"+onSaleType](originTotal,account)
}
//执行
getActualTotal(0,2680.00);//2208
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
🎜 さて、各戦略には独自の独立したスペースがあり、よく整理されているように見えます。しかし、まだ解決されていない問題が 2 つあります: 🎜🎜🎜🎜 プロモーション戦略の増加に伴い、getActualTotal のコード量は依然として増大するでしょう 🎜🎜🎜🎜 システムは柔軟性に欠けています。ストラテジーを追加する必要がある場合は、ストラテジー関数の追加に加えて、switch...case.. ステートメントも変更する必要があります🎜🎜🎜🎜ストラテジー パターンの定義を確認してみましょうもう一度:🎜
定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换

在我们的例子中,每种促销策略的实现方式是不一样的,但我们最终的目的都是为了求得实际金额。策略模式可以把我们对促销策略的算法一个个封装起来,并且使它们可互相替换而不影响我们对实际金额的求值,这正好是我们所需要的。

下面我们用策略模式来重构上面的代码:

var policies={
    "Type_0":function(originTotal){
        return originTotal-Math.floor(originTotal/100)*10 
    },
    "Type_1":function(originTotal){
        return originTotal-Math.floor(originTotal/200)*30 
    },
    ...
    "Type_n":function(originTotal){
        ... 
    }
}
var getActualTotal=function(onSaleType,originTotal,account){
    return policies["Type_"+onSaleType](originTotal,account)
}
//执行
getActualTotal(0,2680.00);//2208
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

分析上面的代码我们发现,不管促销策略如何增加,getActualTotal函数完全不需要再变化了。我们要做的,就是增加新策略的函数而已。

通过策略模式的代码,我们消除了让人反胃的大片条件分支语句,getActualTotal本身并没有计算能力,而是将计算全权委托给了策略函数。

由此我们可以总结出策略模式实现的要点:

  1. 将变化的算法封装成独立的策略函数,并负责具体的计算

  2. 委托函数,该函数接受客户请求,并将请求委托给某一个具体的策略函数

用一张UML图表示如下:
デザインパターンの戦略パターンをフロントエンドで使用する方法

怎么样?现在看到上面这张图是不是有了了然于胸的感觉?那就赶紧去试一试策略模式吧!

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样使用JS+H5实现微信摇一摇

如何对微信小程序进行开发

以上がデザインパターンの戦略パターンをフロントエンドで使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Java フレームワークにおけるデザイン パターンとアーキテクチャ パターンの違い Java フレームワークにおけるデザイン パターンとアーキテクチャ パターンの違い Jun 02, 2024 pm 12:59 PM

Java フレームワークにおけるデザイン パターンとアーキテクチャ パターンの違いは、デザイン パターンがソフトウェア設計における一般的な問題に対する抽象的な解決策を定義し、ファクトリ パターンなどのクラスとオブジェクト間の相互作用に焦点を当てていることです。アーキテクチャ パターンは、階層化アーキテクチャなどのシステム コンポーネントの編成と相互作用に焦点を当てて、システム構造とモジュールの間の関係を定義します。

Java デザイン パターンにおけるデコレータ パターンの分析 Java デザイン パターンにおけるデコレータ パターンの分析 May 09, 2024 pm 03:12 PM

デコレータ パターンは、元のクラスを変更せずにオブジェクトの機能を動的に追加できる構造設計パターンです。抽象コンポーネント、具象コンポーネント、抽象デコレータ、具象デコレータの連携によって実装され、ニーズの変化に合わせてクラス機能を柔軟に拡張できます。この例では、ミルクとモカのデコレーターが総額 2.29 ドルで Espresso に追加されており、オブジェクトの動作を動的に変更するデコレーター パターンの力を示しています。

デザインパターンがコードメンテナンスの課題にどのように対処するか デザインパターンがコードメンテナンスの課題にどのように対処するか May 09, 2024 pm 12:45 PM

デザイン パターンは、再利用可能で拡張可能なソリューションを提供することで、コード メンテナンスの課題を解決します。 オブザーバー パターン: オブジェクトがイベントをサブスクライブし、イベントが発生したときに通知を受信できるようにします。ファクトリ パターン: 具象クラスに依存せずにオブジェクトを作成するための集中的な方法を提供します。シングルトン パターン: クラスには、グローバルにアクセス可能なオブジェクトの作成に使用されるインスタンスが 1 つだけ存在することが保証されます。

Guice フレームワークでのデザイン パターンの適用 Guice フレームワークでのデザイン パターンの適用 Jun 02, 2024 pm 10:49 PM

Guice フレームワークは、次のような多くの設計パターンを適用します。 シングルトン パターン: @Singleton アノテーションによってクラスのインスタンスが 1 つだけであることを保証します。ファクトリ メソッド パターン: @Provides アノテーションを使用してファクトリ メソッドを作成し、依存関係の注入中にオブジェクト インスタンスを取得します。戦略モード: アルゴリズムをさまざまな戦略クラスにカプセル化し、@Named アノテーションを通じて特定の戦略を指定します。

PHP デザイン パターン: テスト駆動開発の実践 PHP デザイン パターン: テスト駆動開発の実践 Jun 03, 2024 pm 02:14 PM

TDD は、高品質の PHP コードを作成するために使用されます。その手順には、テスト ケースを作成し、期待される機能を記述し、テスト ケースを失敗させることが含まれます。過度な最適化や詳細な設計を行わずに、テスト ケースのみが通過するようにコードを記述します。テスト ケースが合格したら、コードを最適化およびリファクタリングして、可読性、保守性、およびスケーラビリティを向上させます。

Java 設計パターンにおけるアダプター パターンの素晴らしい使用法 Java 設計パターンにおけるアダプター パターンの素晴らしい使用法 May 09, 2024 pm 12:54 PM

アダプター パターンは、互換性のないオブジェクトが連携できるようにする構造設計パターンであり、オブジェクトがスムーズに対話できるように、あるインターフェイスを別のインターフェイスに変換します。オブジェクト アダプタは、適応されたオブジェクトを含むアダプタ オブジェクトを作成し、ターゲット インターフェイスを実装することにより、アダプタ パターンを実装します。実際のケースでは、クライアント (MediaPlayer など) はアダプター モードを通じて高度な形式のメディア (VLC など) を再生できますが、クライアント自体は通常のメディア形式 (MP3 など) のみをサポートします。

Reactの主要な機能を理解する:フロントエンドの視点 Reactの主要な機能を理解する:フロントエンドの視点 Apr 18, 2025 am 12:15 AM

Reactの主な機能には、コンポーネント思考、国家管理、仮想DOMが含まれます。 1)コンポーネント化のアイデアにより、UIを再利用可能な部分に分割して、コードの読みやすさと保守性を向上させることができます。 2)状態管理は、状態および小道具を通じて動的データを管理し、変更を変更しますUIの更新をトリガーします。 3)仮想DOM最適化パフォーマンス、メモリ内のDOMレプリカの最小操作の計算を通じてUIを更新します。

Spring MVCフレームワークでのデザインパターンの適用 Spring MVCフレームワークでのデザインパターンの適用 Jun 02, 2024 am 10:35 AM

SpringMVC フレームワークは次の設計パターンを使用します: 1. シングルトン モード: Spring コンテナーを管理します。 2. ファサード モード: コントローラー、ビュー、およびモデルの対話を調整します。 3. ストラテジ モード: リクエストに基づいてリクエスト ハンドラーを選択します。 : アプリケーション イベントを公開し、リッスンします。これらの設計パターンは SpringMVC の機能と柔軟性を強化し、開発者が効率的で保守可能なアプリケーションを作成できるようにします。

See all articles