Strategyパターンを使用したJavaの汎用ファイルパーサーデザイン


14

私は、モジュールの1つの責任がXMLファイルを解析し、データベースに必要なコンテンツをダンプすることである製品に取り組んでいます。現在の要件はXMLファイルの解析のみですが、将来、あらゆる種類のファイルをサポートできるように解析モジュールを設計したいと考えています。このアプローチの理由は、特定のクライアント向けにこの製品を構築しているが、近い将来に他のクライアントに販売する予定だからです。現在のクライアントのエコシステム内のすべてのシステムはXMLファイルを生成および消費しますが、他のクライアントの場合はそうではありません。

これまでに何を試しましたか?(現在) 戦略パターンに基づいた次の設計を念頭に置いています。私はすぐに日食でコードを書き留めてデザインを伝えたので、例外を適切に処理する方法などの他の側面が今のところ無視されるといいでしょう。

Parser:解析メソッドを公開する戦略インターフェイス。

 public interface Parser<T> {
        public T parse(String inputFile);
    }

*ジェネリックパラメーターを使用する理由は、すべての戻り値の型を許可し、コンパイル時に型の安全性を確保するためです。

ProductDataXmlParser製品関連情報を含むproduct.xmlファイルを解析するための具象クラス。(XMLBeanを使用)

public class ProductDataXmlParser implements Parser<ProductDataTYPE> {

    public ProductDataTYPE parse(String inputFile) {
        ProductDataTYPE productDataDoc = null;
            File inputXMLFile = new File(inputFile);

        try {
            productDataDoc = ProductDataDocument.Factory.parse(inputXMLFile);
        } catch(XmlException e) {
            System.out.println("XmlException while parsing file : "+inputXMLFile);
        } catch(IOException e) { 
                 System.out.println("IOException while parsing file : "+inputXMLFile);
        }
        return productDataDoc.getProductData();
    }
} 

ここで、 ProductDataTYPEおよびProductDataDocumentは、xsdおよびscompコマンドを使用して生成されたXMlBean POJOクラスです。

未来

将来解析されるproduct.txtファイルがある場合、ファイルの必要なコンテンツを保持するProductDataという独自のPOJOを定義できます。次に、Parserインターフェースを実装するProductDataFlatFileParserという具象クラスを作成し、ファイルを解析した後、parseメソッドにProductData POJOを設定させます。

このデザインは理にかなっていますか?この設計に明らかな欠陥はありますか?設計が成り立つと、具体的なクラスがアルゴリズムを定義してファイルを解析できるようにし、具体的なクラスにデータを入力する場所を決定させます。設計は、ファイル形式よりもドメインオブジェクトに依存しているようです。これは悪いことですか?設計を改善する方法についてのご意見をいただければ幸いです。


ソフトウェアは、どのファイル形式がサポートされているかを発信者に知らせるべきではありませんか?ソフトウェアはどのパーサーを呼び出すかをどのように知っていますか?
tomdemuyt

実際の実装ではなく、設計に関するフィードバックを探しているので、トピックに関するプログラマーに移行されます。
コードスパークル

@tomdemuyt 工場出荷時のパターンを考える ;)
CKing

2
@botこれをCode Reviewに投稿するように言ったSOユーザーは明らかに間違っていました。投稿する前にサイトのFAQを読むこともできます。「誰かが私にそれをするように言った」は、あなたが何かをする良い理由ではありません。誰もピンポンを演奏していません。誰かが時間を志願して、それを完全に閉じるのではなく、より良い場所を見つけようとしました(コードレビューのトピックから外れているため、有効なオプションだったでしょう)。
ヤニス

2
クロスポストもしないでください。あなたは私たちが掃除しなければならない混乱を作っています。
食い物

回答:


7

私にはいくつかの懸念があります:

  1. 実装する前に、一般的な設計が実際に必要であることを確認します。XML以外のファイルタイプが必要になるのは確かですか?そうでない場合、なぜそれらのためのコードですか?最終的に必要になった場合は、その時点でコードを改良できます。それほど長くはかかりません。おそらく、現在提案しているものとは異なるコードに見える他の要件があり、おそらくとにかく書く必要はないでしょう。彼らが言うように、YAGNI(あなたはそれを必要としません)。
  2. もしあなたが実際に一般的なデザインを必要とし、そしてあなたがこれをかなり確信しているなら、私はそれParser<T>が基本的に健全であると言うでしょう。2つの潜在的な問題があります。(1)ファイル入力を前提としています。たとえば、HTTP応答から取得したJSONストリームを解析しようとしている場合はどうでしょうか。(2)さまざまな種類のデータ用のさまざまな種類のパーサーを使用する、より大きな汎用フレームワークの一部としての場合を除き、必ずしも多くの価値を提供するわけではありません。しかし、このような大規模な汎用フレームワークが必要だとは思いません。私が言える限りでは、非常に単純で具体的なユースケースがあります。XMLファイルをProductDatasのリストに解析します。
  3. でやっているときに例外を飲み込むことは、ほとんど決して良い考えではありませんProductDataXmlParserRuntimeException代わりに何らかの種類に変換します。

1
私たちは多くの外部システムと通信する製品を構築しているので、あらゆる種類のファイル/入力形​​式を考慮することをお勧めします。JSONストリームの優れた点。これがまさに、Parserインターフェイスの解析メソッドにFileパラメーターではなくStringパラメーターを使用させた理由です。ProductDataXmlParserで修正した小さなミスがありました(XmlBeanパーサーにファイルを渡す必要があります)。例外を飲み込むことについても正しいです。私はこのコードを日食ですばやく書き留めて、例を通してstackoverflowの設計を伝えました;)
CKing

うんいいね。私が言っているのは、Parserパラメータを文字列ではなくInputStreamにすることです。:)そして、例外について聞いて良かった-それが実際のコードから切り取られて 'n'貼り付けられたのか、それともStackOverflowのサンプルコードだけだったのかはわかりませんでした。

1
また、多くの外部システムと通信する製品の構築に関しては、具体的な要件なしに汎用コードを構築することをheします。たとえば、少なくとも2つのタイプのオブジェクト、または2つのファイル形式が必要になるまで、汎用のパーサーインターフェイスは作成しません。

あなたの言っていることを考えてみましょう。解析する4種類のデータを含む4種類のxmlファイルがあることを指摘したいと思います。製品データは、システム/製品によって消費されるデータの一種です。
CKing

もう一つ質問があります。戦略パターンの一部であるコンテキストは使用しません。大丈夫ですか?また、汎用パラメーターを取り除き、ParserインターフェイスのparseメソッドでObjectを返します。これは、型パラメーターで宣言されるパーサーを使用するクラスを避けるためです。
CKing

1

あなたのデザインは最良の選択肢ではありません。あなたの設計により、それを使用する唯一の方法:

ProductDataXMLTYPE parser = new ProductDataXmlParser<ProductDataXMLTYPE>().parse(input); 
ProductDataTextTYPE parser = new ProductDataTextParser<ProductDataTextTYPE >().parse(input);

上記の例からあまり多くの利点を見ることはできません。このようなことはできません。

Parser parser = getParser(string parserName);
parser.parse();

ジェネリックを探す前に、次の2つのオプションを検討できます。

  • 1、解析後も同じ出力

データソースがどこから来ても、データベースに保存する前の製品データは同じ形式になります。これは、クライアントとダンプサービスとの間の契約です。したがって、出力と同じProductDataがあると仮定します。インターフェースを簡単に定義できます:

public interface Parser {
    public ProductData parse(String inputFile);
}

さらに、より柔軟にしたい場合は、ProductDataをインターフェイスとして定義します。

パーサーをデータと混合させたくない場合。次の2つのインターフェイスに分割できます。

public interface Parser {
     public void parse(String inputFile);
}
public interface Data {
    public ProductData getData();
}

パーサーは次のようになります。

public class XMLParser implements Parser, Data {} 
public class TextParser implements Parser, Data {}
  • 2、解析後の異なる出力

ProductDataが類似しておらず、Parserインターフェースを再利用したい場合。次の方法でできます:

public interface Parser {
   public void parse(String inputFile);
}

class XMLParse implements {
      @Override
      public void parse(String inputFile);

      ProductDataXML getProductData();        
}

class TextParse implements {
      @Override
      public void parse(String inputFile);

      ProductDataText getProductData();        
}

-2

既に利用可能なものを使用したい場合に備えて、XMLSchema(JAXBが支援)に基づくJRecordBindというJavaライブラリを作成しました。

固定長ファイルを消費/生成するために生まれました。XMLSchemaはその構造を定義するため、プレーンJAXBで使用してXMLファイルをマーシャリング/アンマーシャリングできます。


汎用パーサーを実装するデザインを探しています!私の質問を正しく理解していないと思います。:)
13
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.