戦略パターンの実例


94

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

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

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

戦略パターンが一般的であると考える実例はありますか?

回答:


99

これはどうですか:

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

小さなファイルの場合、「メモリ内」戦略を使用できます。この場合、完全なファイルが読み取られ、メモリに保持されます(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が正しい単語かどうかもわかりません:P)


8
あなたの例は単なるファクトリーパターンではありませんか?また、たとえばC#では機能しないと思います。"getCipher()"メソッドは静的メソッドですが、C#ではインターフェイスに静的メソッドを定義できません(Javaではどちらでもないと思いますが、これについてはわかりません)。
FrenchData

10
彼らは一緒に行きます。ファクトリは戦略を作成しますが、戦略はアルゴリズムを保持して(基本的に)同じ操作を実行します。実行時に戦略を変更することもできます。あなたが正しいファクトリーメソッドについて、私はそれを変更しました。
OscarRyz 2010年

Osacarsポイントを追加するには、工場なしでこれを工場なしで作成できます Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
Abhijit Mazumder

@FrenchDataに同意します。の良い例である一方で、の存在はCipherFactory戦略パターンに慣れていない人を混乱させるかもしれません。
user487772

1
工場パターンは創造的であり、戦略は行動的です。少し違う権利がありますか?
nhoxbypass

61

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

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

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

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

  • ゲーム:プレイヤーは移動時に歩くか走るかを望んでいますが、将来的には、泳いだり、飛んだり、テレポートしたり、地下に潜ったりできるようになるでしょう。

  • 情報の保存:アプリケーションでデータベースに情報を保存する必要がありますが、後でファイルを保存したり、Web呼び出しを行ったりする必要がある場合があります。

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


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

現在、開発の時点では、これらのビジネスルールはまだ完全に明確ではなく、いつでも新しいルールが登場する可能性があります。stragety-patternの威力は、IRulesのリストが与えられた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のビデオシリーズアプリケーションのユニットテスト部分で戦略パターンを使用しています。

彼は人気に基づいてアイテムを表示するページがあるウェブサイトを構築します。ただし、「人気」は多くの場合があり(ほとんどのビュー、ほとんどのサブスクライバー、作成日、ほとんどのアクティビティ、最小限のコメントなど)、管理者がまだ注文方法を正確に知らない場合、さまざまなものを試してみるとよいでしょう。後日注文。orderメソッドを使用してインターフェイス(IOrderAlgorithmなど)を作成し、Ordererオブジェクトに順序付けをIOrderAlgorithmインターフェイスの具体的な実装に委任させます。「CommentOrderer」、「ActivityOrderer」などを作成できます。新しい要件が出てきたら、これらを切り替えるだけです。


これは少し問題の範囲外であることは知っていますが、次に何が起こるのでしょうか?これはInternRule今ありますが、どのようにトリガーしOvertimeRuleますか?OvertimeRule.IsApproved現在呼び出されているロジックが確実に呼び出されるようにするにはどうすればよいInternRule.IsApprovedですか?
Spencer Ruport

13

キーノート:

  1. 戦略は行動設計パターンです。これは、アルゴリズムのファミリーを切り替えるために使用されます。

  2. このパターンには、1つの抽象戦略インターフェースと、そのインターフェースの多くの具体的な戦略実装(アルゴリズム)が含まれています。

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

ウィキペディアの UML図

ここに画像の説明を入力してください

実際の例:航空会社は数か月間(7月から12月)に割引を提供します。月数に応じて料金オプションを決定する運賃モジュールを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による戦略パターン

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


12

私はいくつかのかなり単純な例を考えることができます:

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

    byte [] compress(byte [] input);

    具体的な圧縮クラスは、RunLengthCompression、DeflateCompressionなどです。


9

戦略パターンの一般的な使用法の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);
  }
});

8

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

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

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


これは非常に良い例です。また、コマンドと戦略のパターンの違い、つまり目的を明確に示しています。「メインプログラムは、基本的には、選択した曜日に応じて、マスター戦略」
UTSAV T

7

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

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

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

顧客が異なればこのシステムを使用し、エラーが発生した場合のロールバック/エラー処理要件は異なりました。最初のエラーで配信システムを停止し、ストレージに配信済みのすべてのドキュメントを残し、プロセスを停止して他には何も配信しないことを望んでいました。 ; もう1つは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つの例です。あなた(はい、あなたが読んでいます)が私が間違っていると思ったら、以下にコメントして教えてください。何が戦略パターンの「純粋な」使用を構成するのか、そして私の実装のどの側面が定義に違反しているのかについて知りたいです。戦略インターフェースは少し太っているので、少しおかしいと思います。これまでに見たすべての例では1つの方法しか使用していませんが、これはアルゴリズムをカプセル化していると思います(ビジネスロジックの一部をアルゴリズムと見なすことができる場合はそうです)。

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

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

とにかく、これは非常に複雑な例であり、戦略パターンの使用法はすべて単純すぎる/ばかげているとあなたの気持ちを思わせるかもしれません。他のパターンと組み合わせて使用​​すると、非常に複雑になり、さらに適用性が高まります。


6

ストラテジーパターンは、特に検証と並べ替えアルゴリズムに最もよく使用されるパターンです。

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

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/から取得されています


戦略パターンのさまざまな使用法:検証:コードで実行する必要のある検証がたくさんある場合。異なるアルゴリズム:特に、バブルソートやクイックソートなど、異なるソートアルゴリズムを使用できる場合。情報の保存:データベースやファイルシステムなど、さまざまな場所で情報を保存する場合。解析:解析中に、異なる入力に対して異なる戦略を使用できます。フィルタリング戦略。レイアウト戦略。
Jatinder Pal、2015

5

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


1
受け入れられた答えはこの例について話すことになっていると思いました:)
Jeancarlo Fontalvo

2

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

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

次に、複数のアルゴリズムがあり、一部はパラメータの重み付けに基づいていること、他のアルゴリズムは非常に奇妙で独創的であることに気づきました。最高の人々を選ぶ。

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

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


2

「注文」のステータスが状態パターンではないことを確信していますか?ステータスによって注文の扱いが異なるのではないかと思います。

たとえば、注文の発送方法を見てみましょう。

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

私が見つけた状態パターン(および他のパターン)の最も良い例は、本「Head First Design Patterns」にありました。2番目に近いのは、David Cumpsの一連のブログパターンです。


2

たとえば、2014年10月の第2月曜日など、指定された月と年のn番目のXdayを計算するアルゴリズムを記述したいとします。android.text.format.Time日付を表すためにAndroidの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
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("myemail@example.com", "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

数週間前、私はドメインオブジェクトの1つによって実装された共通のJavaインターフェイスを追加しました。このドメインオブジェクトはデータベースから読み込まれ、データベース表現は約10以上のブランチを持つスタースキーマでした。このように重いドメインオブジェクトを持つことの結果の1つは、重いものではありませんが、同じスキーマを表す他のドメインオブジェクトを作成する必要があったことです。そこで、他の軽量オブジェクトに同じインターフェースを実装させました。そうでなければ、私たちが持っていた:

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

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

元々、私はCollectibleElephantをソートするために使用したかったElephant。すぐに、私のチームメイトCollectibleElephantはセキュリティチェックを実行したり、GUIに送信されるときにフィルターをかけたりするために集まりました。


1

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

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


0

ウィキペディアから

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

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

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

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

戦略パターンがないと、形状と色のデカルト積でクラスの数が増えます。また、インターフェースは実装ごとに変更されます。


0

たとえば、AIの敵を使ったシューティングゲームを想像してみてください。何が起きるかに基づいて、さまざまな方法で継続的に戦ってほしい。

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.