3

問題

私は大きなクラス(約1500 LOC)を持っており、さまざまな「戦略」を使用して、あるオブジェクトから別のオブジェクトにデータを変換します。私はここにそのクラスの表現を持っています:

public class FooService implements FooProcessing {
    FooRequestTransformer fooRequestTransformer;
    AnotherService anotherService;
    InstanceVar1 iVar1;
    InstanceVar2 iVar2;    
...

このクラスが使用するインターフェース(クラスの外部)があります:

interface TransformerStrategy {
    public FooRequest transform(FooResponse response);
}

これは(FooServiceクラス内の)このメソッドに渡されます:

private FooResponse getResponse(FooResponse fooResponse, TransformerStrategy transformerStrategy) {
    FooRequest fooRequest = transformerStrategy.transform();
    fooResponse = anotherService.bar(fooRequest); 
    return fooResponse;
}

getResponse()メソッドを使用してTransformerStrategy匿名で作成するエントリポイントは次のとおりです。

public List<Foo> getFooForSomeFlow1(Param1 param1, Param2 param2, ...){
    FooResponse fooResponse = anotherService.baz(fooRequest);

    TransformerStrategy myTransformerStrategy = new TransformerStrategy() {
        public FooRequest transform(FooResponse fooResponse) {
            fooRequestTransformer.transform(param1, param2, iVar1, iVar2) 
        }
    }

    FooResponse fooResponse = getResponse(fooResponse, myTransformerStrategy);
    ...//other code
}

ここで問題となるのは、(inside )のようないくつかのメソッドがあり、それらはすべて独自の匿名実装を持ち、その後にを呼び出します。ご想像のとおり、これは非常に厄介であり、デバッグ時に混乱します(つまり、ステップインした後、突然戻ってきます)getFooForSomeFlow1()FooServiceTransformerStrategygetResponse()getResponse()getFooForSomeFlow1()

考えられる解決策

考えられる解決策の1つ(頭に浮かぶ)は、これらのさまざまな戦略を「プロバイダー」クラスに編成して、何らかの方法でそれらをグループ化することです。不思議なことに、このクラスにはすでにこのタイプのプロバイダークラスが含まれています。

protected class StrategyProvider {
    public ABCTransformerStrategy newABCTransformerStrategy(FooRequestTransformer transformer, Param1 param1, Param2 param2) {
        return new ABCTransformerStrategy(transformer, param1, param2);
    }
}

protected class ABCTransformerStategy implements TransformerStrategy {
    protected FooRequestTransformer transformer;
    protected Param1 param1; 
    protected Param2 param2;

    //...constructor here

    //...overridden transform method as above
}

コメントの1つには、「テスト目的で匿名クラスを内部クラスに変換した」と書かれています。しかし、彼らはそのうちの1つだけを変換し、残りを残しました。つまり、彼らがリファクタリングのプロセスを開始し、途中で停止したようなものです。

そのため、リファクタリングのプロセスを終了して、すべての匿名クラスを内部クラスに移動し、最終的にこれらのクラスStrategyProviderを外部クラスに移動できると考えていました。問題は、「匿名から内部への変換」によって定型文が追加され(ABCTransformerStrategy上記を参照、すべてのデータをコンストラクターに渡す必要がある)、このリファクタリングプロセスを実行することでどれだけの利益が得られるかがよくわからないことです。

2つの質問があります:

  1. このアプローチを続行する必要がありますか?
  2. または、このコードをより適切で単純化する、適用できる別のデザインパターンはありますか?

ありがとう

4

5 に答える 5

1

あなたのプロバイダークラスは実際にはファクトリパターンであり、まさに私が提案しようとしていたものです。

ロジックをgetFooForSomeFlow1および同様のメソッドから移動することにより、非常に緩く結合されたコードを作成しました。これは常に望ましいことです。

int単に個人的な好みから、インスタンスを返すために使用される、Discriminatorとしての値をとる1つのメソッドがあります。これらのintは、次のように、プロバイダークラス内の静的なfinal変数である可能性があります。

public static final int ABCTransformerStrategy = 1;

さらに、FactoryクラスをAbstractにすることで、使用する必要があるたびにクラスをインスタンス化する必要がなくなり、コードがよりクリーンになります。

編集

提案されてEnumいるように、値を表す具体的なクラスに値を変換するには、使用する方がはるかに望ましく、意味的に正しい方法です。

于 2013-03-06T21:12:01.503 に答える
1

提供したコードサンプルに基づくと、表面的には複雑です。なぜ単純ではないのですか

public List<Foo> getFooForSomeFlow1(Param1 param1, Param2 param2, ...)
{
    FooResponse fooResponse = anotherService.baz(fooRequest);

    FooRequest  fooRequest = fooRequestTransformer
                                 .transform(param1, param2, iVar1, iVar2); 

    FooResponse fooResponse2 = anotherService.bar(fooRequest);
    ...//other code
}

あなたが私たちに見せていない何かが起こっていない限り。

于 2013-03-06T21:14:33.873 に答える
0

関連するオブジェクトを多数提供する場合は、いつでもを使用できますAbstract Factory。シンプルなデザインパターンではありませんが、ここが最適です。

これを見てください:Abstract Factory

于 2013-03-06T21:10:56.420 に答える
0

各メソッドを独自のクラス(メソッドオブジェクトパターン、つまり、method-as-object)に変換します。これは、元のリファクタリングが行われていた場所と似ています。これらすべてのメソッドへのアクセスを一元化する必要がある場合は、オブジェクトとして抽象ファクトリを実装します。説明から、あるタイプから別のタイプに変換しているように聞こえるので、抽象ファクトリに2つのClassパラメータを受け入れさせ、クラスの組み合わせに適したオブジェクトとしてのメソッドインスタンスを呼び出し元に返します。

于 2013-03-06T21:22:17.930 に答える
0

評判の悪いアプローチを試し、メソッドgetResponse()で「インラインメソッド」を試しましたが、重複コードがインライン化されていました(そのため、最初にその重複コードを抽出しgetResponse()ました)。私の質問では、getResponse()私が示したものよりも多くのコードが含まれていることを明確にすべきでした。
ファクトリを作成することに関しては、特にファクトリメソッドや内部クラスに大量のデータを渡さなければならないため、クラスにボイラープレートとLOCを追加することを正当化できませんでした。

代わりに、匿名の内部クラスを次のようなメソッドでラップしました。

private TransformerStrategy createTransformerStrategyWithABCValues(Param1 param1, Param2 param2, IVar ivar, IVar1 ivar2) {
    return new TransformerStrategy() {
        public FooRequest transform(FooResponse response) {
            return FooRequestTransformer.transform(
                    param1,
                    param2,
                    iVar1,
                    iVar2);
        }
    };
}

これで、呼び出しメソッドは次のようになります。

public List<Foo> getFooForSomeFlow1(Param1 param1, Param2 param2, ...){
    FooResponse fooResponse = anotherService.baz(fooRequest);
    TransformerStrategy myTransformerStrategy = createTransformerStrategyWithABCValues(param2, param2, iVar1, iVar2);
    FooResponse fooResponse = getResponse(fooResponse, myTransformerStrategy);
    ...//other code
}

これを行う過程で、5つの戦略に重複があることがわかったので、それを3つの戦略にまとめることができました。提供された内部クラスだけでなく、StrategyProviderクラスも削除しました。

このアプローチにより、デバッグ/保守がいくらか簡単になり、コードからかなりの重複を減らすことができました。

于 2013-03-11T18:11:40.537 に答える