web-dev-qa-db-ja.com

戦略パターンの複数の変数を実装していますか?

コンテンツのシリアライズとデシリアライズを処理するための戦略パターンを実装しようとしています。したがって、4種類の要求、つまりCREATE、RETRIEVE、UPDATE、DELETEがあり、要求ごとに、要求と応答の内容をシリアル化/逆シリアル化する必要があります。

public interface ContentHandler{

    String serializeRequest(Content con)();
    String serializeResponse(Content con)();

    Content deserializeRequest(String str)();
    Content deserializeResponse(String str)();
}

これで4つのクラスができます。

    public class CreateContentHandler implements ContentHandler{
        String serializeRequest(Content con){
           // .........    
        }
        String serializeResponse(Content con){
           // ........
        }  

        Content deserializeRequest(String str){

        }
        Content deserializeResponse(String str){

        }

    }

    public class RetrieveContentHandler implements ContentHandler{
     //.........
    }

    public class UpdateContentHandler implements ContentHandler{
     //.........
    }

    public class DeleteContentHandler implements ContentHandler{
    //.........
    }

現在、JSON、XML、CUSTOM-TYPEなどのさまざまなコンテンツタイプを処理する必要があります。そのため、JSON形式またはXML形式でコンテンツをシリアル化します。

したがって、contenType変数を各関数に渡し、スイッチケースを使用して各関数内のコンテンツを処理することを考えていました。

   String serializeRequest(Content con, ContentType type){
       // ....
       switch(type){
          case JSON:

          case XML: 
       }
    }

しかし、これにより、4つの異なる型の処理により、シリアライズ関数が大きくなると思います。 3つの変数serialize/deserialize、request/response、xml/json/cutomがあります。

新しいインターフェイスまたはクラスを追加して、さまざまなコンテンツタイプを現在のデザインに対応させるにはどうすればよいですか?

編集:いくつかの方法を使用して言及したような方法でシリアル化を行っていません。

String createStringNode(...);  
    String openSubbloc(...);  
    ... // you have to analyze your switch blocks to determine the primitives

ジャクソン(JSONライブラリ)を使用してJSONのシリアル化/逆シリアル化を処理します。だから私がすることは、各リクエストのデータをシリアライズ/デシリアライズするObjectMapperのいくつかのプロパティを設定することです。

// JSON serialization

objectMapperPropertiesBuilder = new ObjectMapperPropertiesBuilder();          
objectMapperPropertiesBuilder.setSerializationFeature(SerializationFeature.WRAP_ROOT_VALUE);                                objectMapperPropertiesBuilder.setInclude(Include.NON_DEFAULT);

jsonPayload = JsonUtils.toJsonString(payload, objectMapperPropertiesBuilder.build());

XMLについても同様に、ライブラリーを使用して、そこでいくつかのプロパティーを設定します。この場合、XMLForamtter、JSONFormatter戦略をどのように実装できますか?

リクエスト/レスポンスの内容はすべて異なるため、シリアライズ/デシリアライズプロセスは異なります(異なるプロパティが設定されます)。

何か不足していますか?

2

GoF による 戦略パターン の目的は、「アルゴリズムのファミリを定義し、それらをカプセル化して、それらを交換可能にすることです。この戦略により、アルゴリズムは、それを使用するクライアントから独立して異なります "

コードでこのパターンを適用し、追求するリクエストに応じて、さまざまな具体的なコンテンツ処理で拒否されるContentHandlerの戦略を作成します。

スイッチアプローチの問題:

ただし、実装では、シリアル化は使用する形式によって異なります。さまざまなswitchブロックを使用してコンテンツタイプを渡す方法では、適切なフォーマットを生成するため、コードの維持が非常に難しくなります。各コンテンツハンドラーの実装は、あらゆる種類のフォーマットを提供する必要があります。ある日、新しいフォーマットを追加したいと想像してください(例 bson ):switchのすべての具体的な実装のすべてのContentHandlerブロックを確認する必要があります。これは大変な作業であり、明らかに 懸念の分離 を強制しません。

代替:

しかし、もっと詳しく見てみると、ここには第2レベルの戦略を追加する機会があります。各switchブロックは、フォーマットを生成するためのコンテンツに対するある種の基本的な操作に対応します。これはアルゴリズムの別のファミリーです。したがって、フォーマットも戦略にする必要があります。

public interface SerialFormatter {
    String createStringNode(...);  
    String openSubbloc(...);  
    ... // you have to analyze your switch blocks to determine the primitives
};

次に、このロジックに従って、すべてのフォーマット固有のプリミティブを再グループ化します。

class JSONFormatter implements SerialFormatter { ... }; 
class XMLFormatter implements SerialFormatter { ... }; 

ある日、新しいフォーマットをサポートしたい場合は、この種類の新しいクラスを追加してください。

その後、シリアライザロジックを簡略化できます。

String serializeRequest(Content con, SerialFormatter fmt){
   // ....
   String s = fmt.openSubbloc ("ID") + 
       fmt.createStringNode ("Name", con.name() ) +
       ...
       fmt.closeSubbloc("ID"); 
   return s;  
 }

結論

複数の戦略の組み合わせを使用した設計は、時々呼ばれます "policy based design" これは非常に強力なアプローチです。n種類のリクエストとm形式で、代わりに単一の責任を持つm + nクラスを記述しますnm個のクラス(質問に対する他の回答を参照)を書き込むか、n個のクラスを書き込み、少なくともnm個の冗長なcasesを書き込みます。

6
Christophe