web-dev-qa-db-ja.com

既存の抽象クラスとそのパラメーターのリファクタリング

抽象メソッドdoStuffを宣言する_abstract class A_があります。現在、Aを継承し、doStuffを実装するクラスが多数あります。

クラスのインスタンスは、ユーザー入力に基づいてAFactoryを介して実行時に初期化されます。元々、すべてのクラスには同じ単一のパラメーター(ユーザー入力)がありました。しかし、Aを継承する新しいクラスだけが必要とする追加のパラメーターがあります。

だから私は次のロジックについてそれを分解します:

  • ユーザー入力(もちろんAFactoryを使用)に基づいてインスタンスを生成するインタープリタークラスは、この余分なパラメーターを認識していませんでした。

    • クラスインタプリタクラスにプッシュしようとすると、ファクトリに渡すタイミングを知る必要があるため、ファクトリをそもそもの目的から外してしまうため、非常に扱いにくくなります。
    • それを期待して盲目的にファクトリーに送るmightそれを使って何かをすることも非常に醜いようです。
  • 私の現在の解決策:一方、A.doStuff(Param param)A.doStuff(AParams params)にリファクタリングすることにしました。

    AParamsは、必要なパラメータを保持でき、doStuffは、興味がない場合は無視できます。これは私にとっても少し厄介なようであり、WIN32APIで構造体を送信することを抑制します。この構造体は、醜く役に立たない多くのパラメーターを保持する可能性があり、私はそれが好きではありません。

この問題に取り組むためのよりエレガントな方法はありますか?それとも私が見落とし、これを解決したいくつかのデザインパターン?

注記

  • Java 1.7を使用しています。
  • クラスの名前は、理論上の設計の問題を強調するためにばかげていますが、実際には通常の意味のある意味のある名前です:)
  • 私はかなり多くのことを検索しましたが、特定の抽象的な理論上の問題をWebで検索することは非常に難しいことがわかりました(このコードでXExceptionをスローする理由とは対照的です)。とにかく尋ねるので、これが重複しているかどうかすみません。

編集1

  • 説明:サブクラス固有の引数をdoStuffメソッドに渡す必要があります。

編集2

  • 私はKilian Fothの意図を完全には理解していなかったので、問題の説明と解決策の理解を深めるのに役立つJava疑似コードをいくつか作成しました。そう:

    これ は私の問題の骨組みです。

    これ は私のソリューションの骨組みです。

    これ は私が何かthinkはキリアンフォスの解決策かもしれませんが、よくわかりません。

8
Scis

ファクトリのポイントは、わずかに異なるクラスからオブジェクトを取得する可能性があるという事実を隠すことです。したがって、これらのオブジェクトのいくつかが特定のデータを必要とし、他のオブジェクトが必要としない場合...

  • 同じ工場で生産できるほど似ていません。次に、複数の工場を持ち、現在よりも早く決断する必要があります。

  • または、それらはあるクライアントがどちらが取得するかを気にする必要がないほど十分に似ています。そうすれば、クライアントが追加のデータを送信するかどうかを気にする必要はありません。つまり、それらはalwaysを渡さなければならないということになりますが、ファクトリはクライアントにその実装の詳細を気にせずに無視することがあります。それ以外のものは、工場が隠蔽することになっていた非常に明確な区別でクライアントに負担をかけるでしょう。

9
Kilian Foth

私は、さまざまなファクトリを含む Builder のようなものを使用してこれを処理します。 Builderには、さまざまなタイプのオブジェクトを作成するためのファクトリーを含むハッシュが与えられ、ハッシュを調べて、任意の基準に基づいて正しいファクトリーを取得します。

たとえば、私には複数の質問タイプがあり、これらすべてはIQuestionFactoryのいくつかの実装によって作成できます。ほとんどのIQuestionFactory実装はBaseQuestionFactoryのサブクラスであり、1つの質問を表すXMLを受け取り、それを質問のルールに従って解析し、BaseQuestionのいくつかのサブクラスを返します。

一部の質問は、フォーム入力の質問である場合、フォームで使用されるフィールドを定義する質問を含むXMLのセクションがある場合など、詳細情報が必要です。これらの質問を作成するファクトリはIEnhancedQuestionFactoryを実装し、ビルダーはQuestionFactoryRegistryから取得したファクトリをチェックし、このインターフェイスを実装しているかどうかを確認します。含まれている場合は、createQuestionメソッドに渡される個別のXMLに加えて、質問を含むファイルの完全なXMLを渡します。

これがいかに柔軟かを示すために、一部のIQuestionFactory実装は、複数の質問ファクトリーを含む単純なシェルであり、着信XMLを調べて内部ファクトリーを呼び出し、作成したものを返すことができます。これは、XMLファイルに複数の質問タイプが含まれている場合に使用します。

ただし、エクササイズ(基本的には質問のコレクションにラップされたコントローラーです)を構築する方法のようなものが必要と思われます。ハッシュ(ExerciseFactoryMap)は、ほとんどの場合デフォルトのファクトリを返すように設定されていますが、場合によっては特定のファクトリが登録されている場合は、それが返されます。さらに、追加のプロパティを持つExerciseサブクラスを作成する特定のFactoryが1つあります。これには、XMLを調べて、そのプロパティを設定するために必要な情報を見つける追加機能があります。

したがって、私は Killian Foth に同意しますaファクトリのポイントは、オブジェクトの実装の詳細を非表示にすることですが構築されていますが、複数のファクトリを創造的な方法で組み合わせることができないということは何もありません(たとえば、実際の作業を行う他のファクトリを含むファクトリ)。

2
Amy Blankenship
  • このような場合の通常のアプローチ(コマンドパターン)では、コンストラクターで追加のパラメーターを渡します。あなたの場合、それは構築中にotherArgumentBに追加することを意味します。

  • ロジックを変えると、いくつかのオプションが開かれる場合があります。たとえば、doStuffをAParamsに移動します。

    for (String arg : listOfArgs) {
        AParams p = AParams.create(arg, otherArgument));
        for (A a : listOfA) {
            p.doStuff(a); // Let AParams to the lifting depending on type of A
        }
    }
    
  • または、プライドを飲み込んで、ループでinstanceofを確認し、otherArgumentを呼び出す前にdoStuffを手動で設定することもできます。

上記が不可能な場合は、現在行っていること(パラメーター引数を広げる)以外に選択の余地はありません。この項目を過度に分析しないでください。

2
Martin Wickman