web-dev-qa-db-ja.com

ポリモーフィズムvs戦略パターン

JavaのStrategyパターンとPolymorphismの違いは何ですか?

ストラテジーパターンを介して達成されることはすべて、基本的に多態性によって可能であると混乱しています。この点で私が間違っていたら訂正してください。

私の混乱を根絶するための例も教えてください。

47
TryinHard

私にとって、CKing投稿からのリンクとウィキペディアの例は十分に明確ですが、私はあなたに与えようとします新しい例。彼らが言ったように、戦略パターンは主に実行時にアルゴリズムの動作を変更する方法です。もちろん、これはさまざまな方法で実現できます(値を保持したり、switch-caseを使用したりすることはできますが、ストラテジーパターンほどうまくいきません)。

2種類のUnitsでターンベースの戦略ゲームを開発しているとしましょう:InfantryおよびTank(Unitのサブクラス)。あなたの地形はPlainsRailroadまたは

class Unit{
    MovementStrategy ms;      
    final int baseMovement;
    int x,y;

    public Unit(int baseMovement){
        this.baseMovement = baseMovement;
    }

    abstract void fire();

    void moveForward(){
        x = x + ms.getHexagonsToMove(baseMovement);
    }

    void setMovementStrategy(MovementStrategy ms){
        this.ms = ms;
    }
}

すべてのUnitサブクラスは、fire()メソッドを実装する必要があります。これは、それらが完全に異なるためです(タンク遠距離重砲弾を撃ち、歩兵はいくつかの短距離弾を撃った。この例では、通常のポリモーフィズム/継承を使用します。これは、fire()メソッドがどのユニットでも実際に異なり、中に変更されないためですゲーム

class Infantry extends Unit{
    public Infantry(){
        super(2);
    }

    void fire(){
        //whatever
    }
}

class Tank extends Unit{
    public Tank(){
        super(5);
    }

    void fire(){
        //whatever
    }
}

ユニットは移動することもでき、歩ける六角形の数を保持するフィールドbaseMovementを持っています。私たちは実際のシミュレーションではなく戦略ゲームを開発しているので、彼らがどのように動くかは気にせず、座標に値を追加したいだけです(この例では、単純なコードを取得するためにX座標のみを使用しています)。 )。すべての地形が同じであれば、戦略オブジェクトは必要ありません...実行時にmove()メソッドの動作を変更する必要があります!

したがって、地形の種類ごとに異なるMovementStrategyクラスを実装し、ゲームでsetMovementStrategyをトリガーするようにプログラムします()各六角形上を移動する任意のユニットに。そして、Unitサブクラスで他に何かを書く必要さえありません。

interface MovementStrategy{
    public int getHexagonsToMove(int base);
}

class PlainMovementStrategy implements MovementStrategy{
    public int getHexagonsToMove(int base){
        return base;
    }
}

class RailroadMovementStrategy implements MovementStrategy{
    public int getHexagonsToMove(int base){
        return base*3;
    }
}

class ForestMovementStrategy implements MovementStrategy{
    public int getHexagonsToMove(int base){
        return (int)(base/2);
    }
}   

ここで、UnitForest内に移動すると、次のように呼び出されます

unit.setMovementStrategy(new ForestMovementStrategy());

そして、それはPlainになり次第、

unit.setMovementStrategy(new PlainMovementStrategy());

これで、地形に応じてユニットの移動距離を変更できるようになり、サブクラスを書き換える必要がなくなりました。

これが違いの理解に役立つことを願っています。

43
rolgalan

ストラテジーパターンを介して達成されることはすべて、基本的に多態性によって可能であると混乱しています。

ハンドルなしでは車を運転できません。これは、ステアリングホイールが車であることを意味するものではありません。同様に、Strategyパターンはポリモーフィズムに依存していますが、それはそれらが同じものであることを意味しません。

Strategyパターンの目的は、継承(is-a)よりも構成(has-a)の使用を促進することです。スーパークラスから動作を継承するクラスの代わりに、別のクラスで動作を定義し、クラスがその動作を参照します。

例としては、良い結果を出す this の答えを見てください。

26
CKing

コアJavaの例を使用した多型対戦略パターン

  • 基本的な違い:ポリモーフィズムはプログラミング言語の概念であり、戦略パターンGoFの行動設計パターンの1つです

  • Polymorphismは、異なるタイプのエンティティへの単一のインターフェースの提供です。
    例:ステアリングホイール(つまり、インターフェース)は、実際のステアリングメカニズムのタイプに関係なく同じです。つまり、ステアリングホイールは、手動ステアリング、パワーステアリング、ラックアンドピニオンステアリングのいずれの場合でも同じように機能します。したがって、ハンドルの操作方法がわかれば、どんなタイプの車でも運転できます。

  • プログラミングでは、Polymorphismは2つの方法で実装されます。

    • 事前バインディング/静的/コンパイル時ポリモーフィズム(例:関数のオーバーロード)
    • 遅延バインディング/動的/実行時ポリモーフィズム(例:関数オーバーライド)

コンパイル時間:開発者であるあなたのコードをコンパイルしている期間。
実行時間:ユーザーがソフトウェアを実行している期間。
ソース

  • Strategy patternは、互換的に使用できる一連のアルゴリズムを定義します。

    • Strategyパターンは動的なパターンです(ソフトウェアでビヘイビアーをどのように実行しますか?)。
    • コアJavaの例:Java.util.Comparator#compare()、特にCollections#sort()によって実行されます。

    • 交通手段戦略的デザインパターンに類似しています。私たちは、車、自転車、バス、ローカル電車などを使用しています。

10
Premraj

あなたが類推を確立している場合:

  • ある場合には、いくつかのオーバーライド可能なメソッドがあります。
  • もう1つのケースでは、いくつかの実装を持つStrategyインターフェイスがあります。

次に、違いはカップリングの程度です。これは最初のケースでは非常に強いですが、2番目のケースでは、ストラテジーの実装に貢献することで、外部コードがクラスのロジックに参加できます。

7
Marko Topolnik

Q:戦略パターンとJavaのポリモーフィズムの違いは何ですか?

最初はこれら2つのアイデアの間に何の関係もないように思われるため、質問は確かに混乱します。

ポリモーフィズムはプログラミングにおけるより広範な概念であり、はいJavaの戦略パターンは 包括的ポリモーフィズム としてカタログ化されたポリモーフィズムの形式を使用して意図を達成しますが、これは存在する唯一のポリモーフィズムのタイプを意味します。これは、後で説明するように、戦略パターンを実装する唯一の方法ではありません。

また、ポリモーフィズムはJavaまたはオブジェクト指向プログラミング言語にのみ存在するものではありません。さまざまな形式のポリモーフィズムがすべてのプログラミングパラダイムに存在し、実装にポリモーフィズムを使用せざるを得ないすべての言語ではありません戦略パターン(関数型言語など)。

このトピックの詳細については、 this other answer を参照してください。継承なしで多型が可能かどうかについて説明しました。パラメトリックおよびアドホック多型など、他のタイプの多型への興味深い参照と例を提供します。

理想的には、これにより、ポリモーフィズムがオブジェクト指向プログラミングの境界を超え、さらに継承とサブタイピングを超える大きな概念であることが明らかになります。

Q:ストラテジーパターンを介して達成されることはすべて、基本的にポリモーフィズムによって可能であると混乱しています。この点で私が間違っていたら訂正してください。

私の観点から見ると、これら2つの概念の関係は、戦略パターンがJavaなどの言語で利用可能な多態性の力を活用してその意図を実装すること、および多態性自体をaと見なすことができることです。パターン。

たとえば、GoFブックの次の引用を考えてみます。

手続き型言語を想定した場合、「継承」、「カプセル化」、「ポリモーフィズム」と呼ばれる設計パターンが含まれている可能性があります。

ポリモーフィズムをパターンとして考えることはほとんどありません。最初に、それは多くのことを意味し、異なる言語で異なる方法で実装されているため、また通常は何らかの形の言語機能として提示されるためです。

Jason Mc C. Smithは、彼の著書「Elemental Design Patterns」で、上記のGoFの引用について次のようにコメントしています。

パターンは言語に依存しない概念です。特定の言語内で特定の言語機能と構成体のセットを使用してそれらを実装すると、形式が取られ、具体的なソリューションになります[...]これは、「Javaデザインパターン」、「C++デザインパターン」について話すのが少し奇妙であることを意味します"、" Websphereデザインパターン "などです。言語やAPIに関係なく、Java、C++、WebSphereなどで実装されたデザインパターンです。

ご覧のとおり、Java実装の観点からStrategyパターンで考えていますが、他の言語パラダイムでは、このようなパターンはおそらく継承を使用せずに異なる方法で実装されている可能性がありますたとえば、純粋な関数型プログラミング言語では、これは 高次関数関数構成 を使用して確実に実装されます。

そのため、これは包含ポリモーフィズムにまったく頼らない戦略パターンの実装になります。関数合成戦略では、他の形の多型(パラメトリックなど)を使用している可能性がありますが、それは戦略パターンの要件ではありません

Q:混乱を解消するための例も教えてください。

上記で説明したように、Javaでは、戦略パターンを実装するために包含ポリモーフィズムを使用することを余儀なくされますが、上記で説明したように、パターンは特定の言語に属するものではないため、戦略パターンを任意の言語の境界の外側にある概念と考えると、他の言語がこれをさまざまな方法で実装していることが容易にわかります。

架空の関数型言語では、ファイルからデータを読み取る関数がある場合があります。ファイルが暗号化されていて、復号化戦略を提供する必要がある場合があります。

function readFile(path: String, decrypt: string -> string) {
    return decrypt(loadFromDisk(path));
}

そして、そのdecrypt引数は、戦略パターンの目的を果たす関数であり、交換可能なアルゴリズムをカプセル化します。

今できる

readFile("customers.txt", aes)
readFile("finance.txt", blowfish)

ここで、aesおよびblowfishは、復号化関数戦略です。

このように機能する言語は、SML、Haskell、JavaScriptなど数十種類あります。

7
Edwin Dalorzo

まず第一に。ポリモーフィズムは、2つの異なることを意味します。最も一般的には、ポリモーフィズムはポリモーフィック型を指します。しかし、あなたはパターンを求めています。

ポリモーフィックコードは、コードの機能が同じままで実行されるたびに変化する可能性があります。簡単な例は、5-1 = 4の代わりに1 + 3 = 4を実行することです。どちらも、異なるコードを使用して同じ結果を達成します。これは、コンピュータウイルスや暗号コードなど、認識されたくないコードに役立ちます。

一方、戦略パターンは、交換可能なアルゴリズムのファミリーを使用しています。これは、テキストを翻訳するときに使用できます。まず、いくつかのコードが言語を決定します。言語がスウェーデン語またはスペイン語の場合、テキストは同じファミリーの異なる関数であるtranslateSwedish()またはtranslateSpanish()によって処理されます。

切り上げます。ポリモーフィックコードは、同じ結果を実現するさまざまなコードを使用します。戦略はより良い結果を達成するために異なるコードを使用していますが。

3
Herman Wilén

このことを考慮

私たちは動物とそれらがどのように動くかを記述するための戦略パターンオブジェクトを持っています...例えば

飛ぶ/泳ぐ/歩く

これらの方法のいずれかを使用する多数の動物(つまり、何千もの異なる動物が飛ぶ)を考えると、多くの異なる動物に同じコードを使用する必要があります。このコードは1か所にのみ存在する必要があるため、簡単に変更でき、不要なスペースを占有しません。

この例では、単純なポリモーフィズムのアプローチにより、大量のコードが重複します。動物とロビンの間に中間クラスを配置するより複雑なアプローチは、動物の動き方が実際にそれを定義するものではないことを考慮に入れていません。さらに、動物が他の戦略オブジェクトを持っている可能性があり、それらはすべて中間クラスを通じて多型にすることができません。

2
Joshua Byer

ポリモーフィズムは原則であり、戦略は設計パターンです

Oracleのドキュメントから page

多型の辞書定義は、生物または種が多くの異なる形態または段階を持つことができる生物学の原理を指します。この原則は、オブジェクト指向プログラミングやJava言語など)の言語にも適用できます。クラスのサブクラスは、独自の動作を定義しながら、親クラスと同じ機能の一部を共有できます。

ポリモーフィズムは、コンパイル時(メソッドのオーバーロード)と実行時(メソッドのオーバーライド)で実現できます。

Strategy_pattern

  1. アルゴリズムのファミリーを定義し、
  2. 各アルゴリズムをカプセル化し、
  3. アルゴリズムをそのファミリ内で交換可能にします。

ストラテジーは、実行時のポリモーフィズムの原理を使用して、目的の機能を実現できます。

StrategyパターンのURLダイアグラムには、Contextと呼ばれるもう1つのコンポーネントがあります。以下のSEの投稿を参照してください。

戦略パターンの実際の例

これはJava戦略パターンに冗長なコンテキストクラスがありますか?

いくつかのより有用な記事:

戦略 ソースメイキング

2
Ravindra babu

ポリモーフィズムの1つの定義は、異なるタイプのエンティティへの単一のインターフェースの提供です。

このことを念頭に置いて、「bird」インターフェースがあり、すべてのbirdクラスが「laysEggs()」メソッドを実装する必要があるとします。そして、「鳥の楽園プログラム」をコーディングし続けると、「fly()」が追加され、ペンギンとキウイのオーバーロードとオーバーライドは実際には飛行できないので不要であることを認識しますが、そのメソッドを実装する必要があります。ダチョウや飛行できない他の人に直面すると、これは退屈で無意味になります。また、泳ぐことができる鳥の数がさらに少ないため、メソッド「swim()」を追加すると最悪です。ご存知かもしれませんが、戦略パターンはこの問題を解決します。

不完全な言葉で言えば、ポリモーフィズムは実践の集まりと考えることができますが、戦略パターンは特定のケースのベストプラクティスです。例:戦略パターンは、実行時にアルゴリズムの動作を選択する必要がある場合に使用されます(交換可能なアルゴリズムを介して)。そして、戦略パターンを介して達成されることは基本的にポリモーフィズムによって基本的に可能であるというのは事実ですが、戦略パターンの知識がなければ、この特定の問題を解決するための「車輪を再発明する」問題が残ります。結論として、一方が他方に基づいていても、それらは非常に異なります。 「Ender Muab'Dib」のコードは、私からのコード例が必要な場合によく説明されているので、そのままにしておいてください。

2
Omar Ayala