Strategyパターンの実装方法と共通処理の適切な置き場所

このQ&Aのポイント
  • Strategyパターンの実装方法について考えます。UseStrategyクラスのように、Strategyインターフェースとその実装クラスを入れ子にする方法も一般的ですが、分けた方が良い場合もあります。
  • 例えば、同じ処理を共有するメソッドがある場合、Strategyインターフェースを抽象クラス化し、共通処理を実装する方法や、UseStrategyクラスに共通処理を実装する方法が考えられます。
  • 一方で、Strategyパターンが適切でない場合もありますので、具体的な要件に基づいて適切な設計を行うことが重要です。
回答を見る
  • ベストアンサー

Strategyパターンを用いた実装について

Strategyパターンを用いた実装について 現在Javaを勉強しており、 Strategyパターンを用いた以下の実装を考えています。 public class UseStrategy { private Strategy strategy; public void doSomthing(int num) { switch (num) { case 0: strategy = new AlphaStrategy(); break; case 1: strategy = new BetaStrategy(); break; case 2: strategy = new GammaStrategy(); break; } // 変数strategyを用いて処理を続行していく // ... } private interface Strategy { public abstract void method_1(); public abstract void method_2(); } private class AlphaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } private class BetaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } private class GammaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } } つきましては、以下ご質問させてください。 (1)Strategyパターンの実装において、  上記UseStrayegyクラスのように、あるクラスの入れ子クラスとして  Strategyインターフェース及び、その実装クラスを実装する方法は  普通でしょうか?    それとも、入れ子クラスとしてではなく、Strategyインターフェース、  その実装クラスを全て 別クラスファイルに分けた方が良いのでしょうか? (2)例として、  BetaStrategy.method_2()とGammaStrategy.method_2()の処理が全く  同じだったとします。その場合、共通となる処理を一つのメソッド化し、  そのメソッドをBetaStrategy.method_2()とGammaStrategy.method_2()から  コールしたいと考えております。  その際、共通となる処理メソッドの実装箇所としては、以下のいずれが良いのでしょうか。   (A)Strategyインターフェースを抽象クラス化し、二つの共通処理メソッドを実装する。  (B)UseStrategyクラスに、共通処理を実装する。    それとも、上記の様なケースがある場合Strategyパターンは不適切でしょうか。 文面に分かりづらい面や、Javaのオブジェクト指向・デザインパターンについて 理解の乏しいところがあるかと思いますが、ご回答の程よろしくお願いいたします。

  • Java
  • 回答数2
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • askaaska
  • ベストアンサー率35% (1455/4149)
回答No.1

(1) ありえないわ。 そもそもinterfaceをprivateな内部interfaceとして定義する必要がないわ。 拡張性を考えたらすべて別クラスとして定義するべきね。 UseStrategyクラスが膨大なコーディング量になってしまうわ。 気持ちは分からなくもないのよ。 ・利用者にはUseStrategyのみを意識してもらう ・Strategyの各クラスは公開したくない っていう考え方でしょう? だったらprotectedにでもすればいいし あとのメンテを考えたら分けた方がいいわよ。 (2) これはStrategyとは関係ない話ね。 答えは、 Strategyとは関係ない別クラスを作成し、その中に処理を記述しそれをコールする よ。 BetaStrategyとGammaStrategyが持つ意味が一部共通なため 同じ処理になるというのであれば、 この2つの親クラスを作成し、そこに実装するのもありね。 でも、特にそうでないというなら 再利用性も考えて先に書いたやり方をするのがいいわ。

hiro_sub
質問者

お礼

ご回答いただきありがとうございます。 お礼の方遅くなりまして申し訳ありません。 >気持ちは分からなくもないのよ。 >・利用者にはUseStrategyのみを意識してもらう >・Strategyの各クラスは公開したくない >っていう考え方でしょう? 見事に。。上記のように考えて、質問に記載したコードを書きました。 ただ、ご指摘にありますように、今後のメンテ、拡張することを考慮し 別クラスにしようと思います。 >これはStrategyとは関係ない話ね。 >答えは、 >Strategyとは関係ない別クラスを作成し、その中に処理を記述しそれをコールする >よ。 ご指摘の通りだと思います。#自分の頭が固かったと思います。。。 無理にでもStrategy内に押し込もうしか考えておりませんでした。 再利用性、拡張することを考え、別クラスを作成しようと思います。 再度自分の書いたコードを見直すと、 色々、考慮不足のコードだったと思います。 #書いた当時はこれしかないのではないかと思っていましたが。。。 ご回答頂いた内容から、検討の足りない面がわかりました。 是非今後に活かしていきたいと思います。本当にありがとうございました。

その他の回答 (1)

回答No.2

Java では'_'は、定数を表す識別子を構成する単語の間以外には使わないのが一般的です。 ほかは、#1の方が仰っている通りです。 interface Strategy { void method1(); void method2(); } class AlphaStrategy implements Strategy { public void method1() { System.out.println("method1 in AlphaStrategy"); } public void method2() { System.out.println("method2 in AlphaStrategy"); } } class BetaStrategy implements Strategy { public void method1() { System.out.println("method1 in BetaStrategy"); } public void method2() { System.out.println("method2 in BetaStrategy"); } } // Gamma extends Beta class GammaStrategy extends BetaStrategy { public void method1() { System.out.println("method1 in GammaStrategy"); } } class SomeThing { private Strategy strategy; void setStrategy(Strategy strategy) { this.strategy = strategy; } void doMethod1() { strategy.method1(); } void doMethod2() { strategy.method2(); } } public class SomeThingUser { public static void main(String[] args) { SomeThing someThing = new SomeThing(); someThing.setStrategy(new AlphaStrategy()); someThing.doMethod1(); someThing.doMethod2(); someThing.setStrategy(new BetaStrategy()); someThing.doMethod1(); someThing.doMethod2(); someThing.setStrategy(new GammaStrategy()); someThing.doMethod1(); someThing.doMethod2(); } }

hiro_sub
質問者

お礼

ご回答頂きありがとうございます。 回答が遅くなりまして、申し訳ありません。 >Java では'_'は、定数を表す識別子を構成する単語の間以外には使わないのが一般的です。 つい、C言語の癖で、'_'を付けていました。 今後は、'_'を付けないように気をつけたいと思います。 また、(1)、(2)の疑問・問題を解決したコードを提示頂きありがとうございます。 提示頂きましたコードを参考に、自分のコードを書き直したいと思います。

関連するQ&A

  • 肥大化した実装クラスを分割する方法は?

    お世話になります。 javaで開発を行っているのですが、クラスファイルのソースが肥大化したので行数を減らすべくクラス分割を行いたいと考えています。(CheckStyleの定義で規定行数を超えたため) 現在、あるサービスクラスがあり、実装クラス側分割の方法としてexportとimportそれぞれ分割したいのですが、具体的な方法がわかりません。 現在の実装を下記に書いてみます。 ※jdk1.5.0_09を使用しています //インターフェース public interface HogeService {   void export(Integer param1, Integer param2);   void import(Integer param1, Integer param2); } //実装クラス public final class HogeServiceImpl implements HogeService {   //export implement   public void export(Integer param1, Integer param2) {     実装   }   //export sub method   private void exportSubMethod1() {     実装   }   //import implement   public void import(Integer param1, Integer param2) {     実装   }   //import sub method   private void importSubMethod1() {     実装   } } importとexportには共通するメソッドはなく、単純に2つのクラスにソース分割できればと考えております。

    • ベストアンサー
    • Java
  • キャストの仕方がわかりません

    キャストの仕方がわかりません メソッド内でクラスを生成し、 そのクラスで共通処理を行いたいのですが、上手くいきません。 ジェネリクスの使い方が悪いのか、キャストで怒られてしまいます。 お分かりの方、いらっしゃいましたら教授願えますか。 以下、ソースです。 interface ToolInterface { /** 結果 */ public abstract Object toolResult(); } class TestA implements ToolInterface{ @Override public Object toolResult() { return "Aです"; } } class TestB implements ToolInterface{ @Override public Object toolResult() { return "Bです"; } } public class TestMain { public static void main(String args[]) { TestMain me = new TestMain(); me.dispResult(TestA.class); me.dispResult(TestB.class); } /** このメソッドでインスタンス化及び処理を行う */ private void dispResult(Class<?> obj) { try { obj.newInstance(); //ここでキャストか何かして表示させたい ToolInterface resObj = (ToolInterface) obj; System.out.println(resObj.toolResult()); } catch (InstantiationException e) { } catch (IllegalAccessException e) { } } }

    • ベストアンサー
    • Java
  • JAVAの問題

    この問題がわかりません。クラス図を作成するみたいなんですがまったくわかりません。 class Context{ public void contexInterface(){ } } interface Strategy{ public void AlgorithmInterface(); } class ConcreteStrategy implements Strategy{ public void AlgorithmInterface(){ } }

  • 「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」

    「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」は正しい? はじめまして。Javaのインタフェースに関する質問です。 私はこれまで、インタフェースを使うときは、インタフェースを実装してクラスを宣言し、そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する、と理解していました。 しかし、下の例をみてください。抽象メソッドの定義を、インタフェースの実装の以前で与えています。問題無くコンパイルでき、実行できます。実行結果も以下の通りです。 インタフェースの抽象メソッドへの定義の与え方やその実行のされ方は、メソッドのオーバーライドと同様と思っていましたので、下記のコードでは「クラスBが抽象クラスではありません」や、「インタフェースの抽象メソッドがオーバーライドされていません」などの文法エラーがでると思っていました。 そこで、質問です。 インタフェースが持つ抽象メソッドの定義を与える場所について、または、これに関する説明のあるページなど、何かご存知でしたら教えてください。 ★コード★ interface X{   void show(); } class A{   public void show(){     System.out.println("A");   } } class B extends A implements X{ } public class Main{   public static void main(String[] args){     X x=new B();     x.show();   } } ★実行結果★ >java Main A ★Java環境★ java 1.6.0_21 javac 1.6.0_16

    • ベストアンサー
    • Java
  • C++ 振る舞いの動的な変更

    似たような動作をする、複数の処理があるのですが、それらをひとつのインターフェースで、モード切り替えで実行できるようにしたいのですが、良い方法はありますでしょうか? 下はクラスでの例です。 class SuperClass {  virtual static void method_1() = 0;  virtual static void method_2() = 0;  ... } class classA : public SuperClass {  static void method_1() {}  static void method_2() {}  ... }; class classB : public SuperClass {  static void method_1() {}  static void method_2() {}  ... }; // 処理だけですので、メンバ変数はありません XXX::mode = A; XXX::mehod_1(); // classA のメソッドが呼ばれる。 XXX::mode = B; XXX::mehod_1(); // classB のメソッドが呼ばれる。 方法としては、クラスでも関数ポインタでも何でもかまわないんですが、 関数が複数あるため、クラスにしてまとめて変更ができると楽なのですが、 実体は特になく、static なメンバ しかないので、名前空間になるのか、、、、 どのように実装してよいか悩んでいる状態です。 よろしくお願いいたします。

  • インターフェイス実装クラスの表示について

    /* インタフェースPlanetを実装したクラスEarth、Marsがあります。  以下の実行結果になるようにクラスAggregateへshowメソッドを  追加してください。 [実行結果] 地球 太陽系にある惑星の1つで、太陽から3番目に近い。・・・ 火星 太陽系の太陽に近い方から4番目の惑星である。・・・ */ // [Planet.java] // 実装したいPlanetクラス interface Planet {   public String getName();   public String getOutline(); } // Planetを実装したEarthクラス // [Earth.java] class Earth implements Planet {   private final String name="地球";   // getNameメソッド:戻り値String、引数無し   public String getName(){    return name;   }   // getOutlineメソッド:戻り値String、引数無し    public String getOutline(){      return "太陽系にある惑星の1つで、太陽から3番目に近い。・・・";    } } // Planetを実装したMarsクラス // [Mars.java] class Mars implements Planet {   private final String name="火星";   // getNameメソッド:戻り値String、引数無し   public String getName(){     return name;   }   // getOutlineメソッド:戻り値String、引数無し   public String getOutline(){     return "太陽系の太陽に近い方から4番目の惑星である。・・・";   } } // メインクラス // [Main.java] class Main{   public static void main(String[] args){   // Earth&Marsクラスのインスタンス化    Earth earth = new Earth();     Mars mars = new Mars();   // Aggregateクラスのインスタンス化   Aggregate aggregation = new Aggregate();   // showメソッド呼び出し:戻り値無し、引数earth・mars    aggregation.show(earth);    aggregation.show(mars); } } // [Aggregate.java] class Aggregate { // ここにshowメソッドを追加   public void show(Earth planet){     System.out.println();   }   public void show(Mars planet){     System.out.println();   }  } showメソッドに引数としてEarth planet,Mars planetを渡すというところまでは理解しています。後は星の名前と概要を表示するのですが、例えば、 showメソッド内 // ここにshowメソッドを追加 public void show(Earth planet){ String str = earth.getName(); System.out.println(str); } public void show(Mars planet){ String str2 = mars.getOutline(); System.out.println(str2); } } とすると、erathとmarsの部分が「シンボルがありません」のエラーになります。自分の認識としては、EarthクラスとMarsクラスでフィールド変数を宣言しているので使えるのでは?と思っていたのですが、全然違うようです。どなたかどちらかのコード例を表記して頂けないでしょうか?よろしくお願い致します。

    • ベストアンサー
    • Java
  • C++で参照カウンタを実装したいのですが

    こんにちは。 C++でクラスに参照カウンタを実装したいのですが、もしも実装する場合、 class CRefCounter {   参照カウンタとAddRef、Releaseメソッドを仮想メソッドとして実装 }; このクラスを継承して直接使う方法と、 class IRefCounter {   参照カウンタとAddRef、Releaseメソッドを純粋仮想メソッドとして宣言 } このクラスを継承して継承側で実装する方法とがあると思うのですが普通はどちらを使うものでしょうか?

  • c# この高速化の方法あり? 2

     こんにちは、c#初心者です。  現在ライブラリを作成しているのですが、その中でちょっと問題がありそうな高速化の方法を思いついたので質問させていただきました。  継承させるクラスを作るときに、継承予定のクラスで実装するメソッドやメンバを、基のクラスでは public class Class1 {   internal virtual void Method()   {     throw new NotImplementedException();   } } // - - - - - - - - - - - - - - - - - - - - - - - - - public class Class2 {   internal override void Method()   {     //ここで実装   } } として、 このオブジェクト「sampleObj」があったとして、 if ( sampleObj is Class2 )   sampleObj.Method(); のようにすることで Class2 temp = sampleObj as Class2; if ( temp != null )   temp.Method(); や if ( sampleObj is Class2 )   ((Class2)sampleObj).Method(); のようにすることよりも若干高速になるようです。  末端のアプリケーションならまだ問題になりにくいかもしれませんが、今回はライブラリということなので気になっています。  気休め程度に「internal」になっていますがそれでもまずい気がします。  どなたか詳しい方がいらっしゃいましたら教えていただけませんか?

  • singletonによるインターフェイスの実装

    Java勉強中の初心者です。 標題の件についてお願いします。 以下、簡単に条件を説明させていただきます。 Aクラス = メインクラス Bクラス = インターフェイスクラス Cクラス = DとEを動的に生成するクラス Dクラス = インターフェイスを実装するクラス Eクラス = インターフェイスを実装するクラス AクラスにB.getInstance(name)があります。 for文の無限ループがあります。 Cクラス class C { public static B getInstance(String name) { // Aクラスのaと変数nameが比較して一致したら // Dクラスのインスタンス生成 // 一致しなかったらEクラスのインスタンス生成 if(A.a.equals(name)){ return D.getInstance(); }else{ return E.getInstance(); } } } Dクラス class D implements B{ private D() { } public static D getInstance() { D d = new D(); return d; } // インターフェイスでのメソッド省略します。 } Eクラス class E implements B{ private E() { } public static E getInstance() { E e = new E(); return e; } // インターフェイスでのメソッド省略します。 } この条件の時にnewするたびにインスタンスが 生成されてしまいます。 インスタンスの生成が一度だけしか 生成されないようにするには、C,D,Eクラスで どのように記述すればいいか悩んでいます。 (骨組みは書けましたが) クラスを簡単に省略してわかりづらいと 思いますがよろしくお願いします。

    • ベストアンサー
    • Java
  • インタフェイス実装と抽象クラス継承を同時に使うには??

    私はjava初心者です、今練習問題で困っています。 1つのクラスに抽象クラスとインターフェイスを 実装することはできるのでしょうか? 例えば abstract class Car { private String gas; public void getGas(int gas) { this.gas = gas; } public abstract void enjin(); } interface Flying extends Pet { void show(); } 上のインタフェイスと抽象クラスを同時に下のクラスに継承、実装しよう とすると、どんな風にかけば良いのでしょうか class Zoon { public Zoon() { super(); } public void enjin() { System.out.println("どどどどど"); } public void show() { System.out.println("いいくるまだ"); } }

    • ベストアンサー
    • Java

専門家に質問してみよう