web-dev-qa-db-ja.com

戦略パターンの実世界の例

OCPプリンシパル と、これを達成するための戦略パターンの使用方法について読んでいます。

これを何人かの人に説明しようとしましたが、考えられる唯一の例は、「注文」のステータスに基づいて異なる検証クラスを使用することです。

私はオンラインでいくつかの記事を読みましたが、これらは通常、レポート/請求書/検証などを生成するなど、戦略を使用する本当の理由を説明していません...

戦略パターンが一般的だと思う実世界の例はありますか?

88
Tired

これはどうですか:

ファイルを暗号化する必要があります。

小さなファイルの場合、「メモリ内」戦略を使用できます。この戦略では、完全なファイルが読み込まれ、メモリ内に保持されます(ファイル<1 gbの場合)

大きなファイルの場合は、ファイルの一部がメモリに読み込まれ、部分的に暗号化された結果がtmpファイルに保存される別の戦略を使用できます。

これらは、同じタスクに対する2つの異なる戦略です。

クライアントコードは同じように見えます。

 File file = getFile();
 Cipher c = CipherFactory.getCipher( file.size() );
 c.performAction();



// implementations:
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             // load in byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

     Cipher c = CipherFactory.getCipher( file.size() );

暗号の正しい戦略インスタンスを返します。

これがお役に立てば幸いです。

(Cipherが正しいWordであるかどうかさえわからない:P)

94
OscarRyz

繰り返しますが、古い投稿ですが、検索は引き続き有効になるため、さらに2つの例を追加します(コードはC#です)。プロジェクトマネージャーが「アプリケーションに「X」を実行させたいが、「X」はまだ明確ではなく、近い将来変更される可能性があります」と言うとき、私は何度も何度も助けてくれたので、戦略パターンが大好きです。 」これ 戦略パターンを説明するビデオ 、例としてStarCraftを使用しています。

このカテゴリに該当するもの:

  • 並べ替え:これらの数値を並べ替えたいのですが、BrickSort、BubbleSort、またはその他の並べ替えを使用するかどうかはわかりません

  • 検証:「いくつかのルール」に従ってアイテムをチェックする必要がありますが、そのルールが何であるかはまだ明確ではなく、新しいルールを考えるかもしれません。

  • ゲーム:プレイヤーは、移動するときに歩いたり走ったりしたいのですが、将来的には、泳いだり、飛んだり、テレポートしたり、地下に穴を掘ったりできるようになるはずです。

  • 情報の保存:アプリケーションがデータベースに情報を保存することを望んでいますが、後でファイルを保存したり、ウェブコールをしたりする必要があるかもしれません

  • 出力:Xをプレーンな文字列として出力する必要がありますが、後でCSV、XML、JSONなどになる場合があります。


ユーザーがデータベース内のユーザーに製品を割り当てることができるプロジェクトがあります。この製品の個人への割り当てのステータスは「承認済み」または「不承認」のいずれかであり、一部のビジネスルールに依存しています。たとえば、ユーザーが特定の年齢の人に製品を割り当てた場合、そのステータスは拒否されます。アイテムの2つのフィールドの差が50より大きい場合、ステータスは拒否されます。

現在、開発の時点では、これらのビジネスルールはまだ完全に明確ではなく、いつでも新しいルールが登場する可能性があります。戦略パターンの威力は、IRuleのリストが与えられたRuleAgentを作成したことです。

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

製品を人に割り当てる時点で、RuleAgentを作成し、ルールのリスト(すべてがIRuleを実装します)を渡し、割り当ての検証を依頼します。ルールをすべて実行します。これらはすべて同じインターフェイスを実装しているため、すべてにIsApprovedメソッドがあり、いずれかがfalseを返す場合はfalseを返します。

たとえば、マネージャーが突然現れて言ったら、インターンへのすべての割り当て、または残業している人へのすべての割り当ても拒否する必要があります...このような新しいクラスを作成します。

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

Ifステートメントまたはコードを追加または削除し続ける必要はなく、IRUleインターフェイスを実装する新しいルールクラスを作成し、必要に応じてそれらを切り替えるだけです。


別のすばらしい例:Scott Allenのビデオシリーズ http://www.asp.net/mvc/pluralsight では、アプリケーションの単体テスト部分で戦略パターンを使用しています

彼は、人気に基づいてアイテムを表示するページを持つWebサイトを構築します。ただし、「人気」にはさまざまなもの(ほとんどのビュー、ほとんどの購読者、作成日、ほとんどのアクティビティ、コメントの最小量など)があり、管理者がまだ注文方法を正確に把握していないため、後日注文。注文メソッドを使用してインターフェース(IOrderAlgorithmまたは何か)を作成し、Ordererオブジェクトに、注文をIOrderAlgorithmインターフェースの具体的な実装に委任させます。 「CommentOrderer」、「ActivityOrderer」などを作成できます。そして、新しい要件が発生したらこれらを切り替えるだけです。

53
Céryl Wiltink

いくつかの非常に単純な例を考えることができます。

  • リストの並べ替え。戦略は、リスト内の2つの項目のどちらが「最初」であるかを決定するために使用される比較です
  • 実行時にソートアルゴリズム自体(QuickSort、HeapSortなど)を選択できるアプリケーションがあります。
  • Log4Net および Log4j のアペンダー、レイアウト、およびフィルター
  • レイアウトマネージャー UIツールキット
  • データ圧縮。唯一のメソッドが次のように見えるICompressorインターフェイスがある場合があります。

    byte [] compress(byte [] input);

    具体的な圧縮クラスは、RunLengthCompression、DeflateCompressionなどのようになります。

12
Eric Pohl

キーノート:

  1. Strategyは動作デザインパターンです。アルゴリズムのファミリーを切り替えるために使用されます。

  2. このパターンには、そのインターフェースの1つの抽象戦略interfaceと多くのconcrete戦略実装(algorithms)が含まれます。

  3. アプリケーションは、戦略interfaceのみを使用します。構成パラメーターによっては、具体的な戦略インターフェイスにタグ付けされます。

wikipedia のUML図

enter image description here

Wordの実際の例:数ヶ月(7月〜12月)に割引を提供する航空会社Fareモジュールを1つ使用できます。このモジュールは、月数に応じて価格設定オプションを決定します。

簡単な例を見てください。この例は、オンライン小売アプリケーションに拡張でき、特別な日/ハッピーアワーのショッピングカートアイテムに簡単に割引を提供します。

import Java.util.*;

/* Interface for Strategy */
interface OfferStrategy {
    public String getName();
    public double getDiscountPercentage();
}
/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0;
    }
}
/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0.25;
    }
}
/* Context is optional. But if it is present, it acts as single point of contact
   for client. 

   Multiple uses of Context
   1. It can populate data to execute an operation of strategy
   2. It can take independent decision on Strategy creation. 
   3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals
   4. Code re-factoring will become easy
*/
class StrategyContext {
    double price; // price for some item or air ticket etc.
    Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>();
    StrategyContext(double price){
        this.price= price;
        strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy());
        strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy());        
    }
    public void applyStrategy(OfferStrategy strategy){
        /* 
        Currently applyStrategy has simple implementation. You can use Context for populating some more information,
        which is required to call a particular operation            
        */
        System.out.println("Price before offer :"+price);
        double finalPrice = price - (price*strategy.getDiscountPercentage());
        System.out.println("Price after offer:"+finalPrice);
    }
    public OfferStrategy getStrategy(int monthNo){
        /*
            In absence of this Context method, client has to import relevant concrete Strategies everywhere.
            Context acts as single point of contact for the Client to get relevant Strategy
        */
        if ( monthNo < 6 )  {
            return strategyContext.get(NoDiscountStrategy.class.getName());
        }else{
            return strategyContext.get(QuarterDiscountStrategy.class.getName());
        }

    }
}
public class StrategyDemo{    
    public static void main(String args[]){
        StrategyContext context = new StrategyContext(100);
        System.out.println("Enter month number between 1 and 12");
        int month = Integer.parseInt(args[0]);
        System.out.println("Month ="+month);
        OfferStrategy strategy = context.getStrategy(month);
        context.applyStrategy(strategy);
    }

}

出力:

Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0

Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0

有用な記事:

戦略 dzoneによるパターン

戦略 ソースメイキングによるパターン

11
Ravindra babu

戦略パターンの一般的な使用法の1つは、カスタムのソート戦略を定義することです(高階関数のない言語で)。 Javaで文字列のリストを長さでソートし、匿名の内部クラス(ストラテジーインターフェイスの実装)を渡します:

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

同様に、オブジェクトデータベースを使用したネイティブクエリに戦略を使用できます。 db4oの場合:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});
9
Fabian Steeg

エンタープライズディレクトリに対して毎日ユーザーベースを同期するアプリケーションがあります。ユーザーは、大学でのステータスに基づいて資格があるか、資格がありません。プロビジョニングプログラムは毎日実行され、資格があると想定されるユーザーがアプリケーションでプロビジョニングされ、プロビジョニングされていないユーザーはプロビジョニングが解除されます(実際にはグレースフルデグラデーションアルゴリズムに従いますが、それは重要なことです)。土曜日に、各ユーザーの一部のプロパティを同期し、適切な適格性があることを確認する、より徹底的な更新を行います。月末に、その月の使用量に基づいて請求処理を行います。

構成可能な戦略パターンを使用して、この同期を行います。メインプログラムは基本的に、曜日(同期の変更のみ/すべて同期)とアカデミックカレンダーに対する学期の時間に応じてマスター戦略を選択します。請求サイクルが終了している場合、請求戦略で構成されます。次に、選択した戦略を標準インターフェイスを介して実行します。

これがどれほど一般的かはわかりませんが、戦略パターンにぴったりだと感じました。

8
tvanfosson

これは古い質問ですが、最近実装した別の興味深い例があると思います。

これは、ドキュメント配信システムで使用されている戦略パターンの非常に実用的な例です。

PDF配信システムがあり、大量のドキュメントとメタデータを含むアーカイブを受け取りました。メタデータに基づいて、ドキュメントを配置する場所を決定しました。たとえば、データに応じて、ドキュメントをAB、またはCストレージシステム、または3つの組み合わせで保存します。

さまざまな顧客がこのシステムを使用し、エラーが発生した場合のロールバック/エラー処理要件が異なりました。最初のエラーで配信システムを停止し、すべてのドキュメントを既にストレージに配信したままにします。 ;別の人は、Bに保存するときにエラーが発生した場合にCからロールバックすることを望みましたが、Aに既に配信されたものはすべて残します。 3番目または4番目のニーズにも異なるニーズがあることは容易に想像できます。

この問題を解決するために、配信ロジックと、すべてのストレージからのものをロールバックするメソッドを含む基本的な配信クラスを作成しました。エラーが発生した場合、これらのメソッドは実際には配信システムによって直接呼び出されません。代わりに、クラスは依存性注入を使用して「システムを使用する顧客に基づいた」「ロールバック/エラー処理戦略」クラスを受け取ります。このクラスはエラーの場合に呼び出され、エラーに応じてロールバックメソッドを呼び出します。

配信クラス自体は、戦略クラスに何が起こっているか(どのドキュメントがどのストレージに配信されたか、どのような障害が発生したか)を報告し、エラーが発生するたびに、戦略を続行するかどうかを尋ねます。戦略が「停止」と言う場合、クラスは戦略の「cleanUp」メソッドを呼び出します。このメソッドは、以前に報告された情報を使用して、配信クラスから呼び出すロールバックメソッドを決定するか、単に何もしません。

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

そこで、2つの異なる戦略があります。1つはQuitterStrategy(最初のエラーで終了して何もクリーンアップしない)と、もう1つはMaximizeDeliveryToAStrategy(可能な限りしようとしないプロセスを中止し、ストレージAに配信されたものをロールバックしませんが、Bへの配信が失敗した場合、Cからのものをロールバックします)。

私の理解では、これは戦略パターンの一例です。あなた(はい、あなたが読んでいる)が私が間違っていると思うならば、以下にコメントして、知らせてください。私は、戦略パターンの「純粋な」使用を構成するもの、および私の実装のどの側面が定義に違反するのかについて興味があります。戦略インターフェースが少し太っているので、ちょっとおかしいと思います。これまで見てきたすべての例では1つのメソッドしか使用していませんが、これはまだアルゴリズムをカプセル化していると思います(ビジネスロジックの一部をアルゴリズムと見なすことができる場合はそうします)。

戦略は配信の実行中にイベントについても通知されるため、 Observer と見なすこともできますが、これは別の話です。

少し調べてみると、これは Advisor と呼ばれる「複合パターン」(MVCなど、特定の方法で下に複数のデザインパターンを使用するパターン)のようです。これは、配信を続行するかどうかのアドバイザーですが、要求されたときにロールバックできるため、アクティブなエラーハンドラーでもあります。

とにかく、これは非常に複雑な例であり、戦略パターンの使用法がすべて単純すぎる/馬鹿げているという感覚をあなたに与えるかもしれません。他のパターンと組み合わせて使用​​すると、非常に複雑になり、さらに適用可能になります。

7

戦略パターンは、検証とソートアルゴリズムに特によく使用されるパターンです。

簡単な実用例で説明しましょう

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

これのテストコードは

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

同じ例が http://coder2design.com/strategy-pattern/ から取られています

6
Jatinder Pal

戦略パターンの良い例は、異なるキャラクターを持つことができ、各キャラクターが攻撃する複数の武器を持つことができるが、一度に1つの武器しか使用できないゲームの場合です。したがって、コンテキストとしてのキャラクター、たとえば、King、Commander、Knight、Soldier、および武器としての戦略があります。ここで、attack()は使用する武器に依存するメソッド/アルゴリズムになります。したがって、具体的な武器クラスがSword、Axe、Crossbow、BowAndArrowなどである場合、それらはすべてattack()メソッドを実装します。これ以上の説明は不要だと思います。

5

「注文」のステータスがStateパターンではないことを確認しますか?私は、注文がそのステータスに応じて異なる方法で処理されないという予感を持っています。

注文のメソッドShipを例にとります:

order.Ship();
  • 配送方法のステータスが機能によって異なる場合は、戦略パターンがあります。
  • ただし、Ship()メソッドが成功するのは、注文が支払われ、注文がまだ出荷されていない場合のみです。状態パターンがあります。 。

状態パターン(および他のパターン)の最良の例は、「 Head First Design Patterns 」という本にありました。これは驚くべきことです。すぐ近くに David Cumpsの一連のブログのパターン があります。

2
grootjans

たとえば、2014年10月の第2月曜日など、特定の月と年のnth Xdayを計算するアルゴリズムを作成するとします。AndroidのTimeクラスAndroid.text.format.Timeを使用して、日付だけでなく、Java.util.Calendarにも適用できる汎用アルゴリズムを作成することもできます。

これは私がやったことです。

DatetimeMath.Javaの場合:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

TimeMath.Javaの場合:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

OrdinalDayOfWeekCalculator.Javaで、汎用アルゴリズムを持つクラス:

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

Androidアプリでは、

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

Java.util.Calendarに同じアルゴリズムを再利用したい場合は、DatetimeMathの3つのメソッドを実装するCalendarMathクラスを作成してから、

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);
2
anomal

非常に複雑なデータベースを持つエンタープライズプラットフォーム用のサードパーティプロビジョニングインターフェイスを作成する必要がありました。プロビジョニングされるデータの送信は、アプリケーションの優先度キューに入れられたデータ型のリストとして行われ、依存関係によりデータベースに正しい順序で書き込まれます。

そのデータを書き込むプロセスは非常に簡単で、優先度キューの先頭から飛び出し、抽出するオブジェクトのタイプに基づいて戦略を選択しました。

1
Coxy

数週間前、ドメインオブジェクトの1つによって実装された共通のJavaインターフェイスを追加しました。このドメインオブジェクトはデータベースからロードされ、データベース表現は約10のスタースキーマでした+ブランチ:このような重いドメインオブジェクトを持つことの結果の1つは、同じスキーマを表す他のドメインオブジェクトを作成する必要があったことです。我々は持っていた:

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

もともと、CollectibleElephantを使用してElephantsをソートしたかったのです。かなり早く、私のチームメイトはCollectibleElephantにグロミングし、セキュリティチェックを実行したり、GUIに送信されたときにフィルタリングしたりします。

1
Alan
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by Paypal
        cart.pay(new PaypalStrategy("[email protected]", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}
1
Vivek Goel

良い例であるアプリケーションのかなり複雑なエンジンで戦略アプローチを使用しました。本質的にエンジンの役割は、ウィジェットを持っている人のリストを見つけて最初に見つけることでした。2番目の役割は、未知の数のパラメーター(以前のビジネスの価格距離など) 、在庫の金額、配送オプションなどなど...)

本質的に私たちがやったことは、問題を2つの戦略に分割することでした。最初はデータ取得でした。ウィジェットの複数のソースがあり、データを取得してそれを共通構造に変換する必要があることがわかっていたためです。

また、複数のアルゴリズムがあり、一部はパラメータの重み付けに基づいており、他のアルゴリズムは非常に奇妙で不適切であり、visiosとチャートを引き出しずに正義を行うことはできませんでした。最高の人を選ぶ。

私たちのサービス自体は、入力、出力を本質的に定義し、データの正規化を行ったものです。また、プロバイダーパターンを使用して、戦略を使用したアプリケーション固有のデータプロバイダーとアルゴリズムプロバイダーをプラグインしました。これはかなり効果的なシステムでした。

解決できない戦略またはテンプレートパターンを使用しているかどうかについて、いくつかの議論がありました。

1
JoshBerke

ウィキペディアから

コンピュータープログラミングでは、戦略パターン(ポリシーパターンとも呼ばれます)は、実行時にアルゴリズムを選択できるようにする動作ソフトウェア設計パターンです。単一のアルゴリズムを直接実装する代わりに、コードは、アルゴリズムのファミリーのどのアルゴリズムを使用するかに関する実行時の指示を受け取ります

Windowsペイントアプリケーションでは、さまざまなセクションで個別に形状と色を選択できる戦略パターンを確認できます。ここで、形状と色は、実行時に変更できるアルゴリズムです。

「RedCircle」のオプションを提供するのではなく、赤色で円を描きたい場合は、円と選択した色を選択できます。

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

戦略パターンがないと、形状と色のデカルト積を使用してクラスの数が増加します。また、実装ごとにインターフェースが変わります。

0
bharanitharan