web-dev-qa-db-fra.com

Conception d'un analyseur de fichiers générique en Java utilisant le modèle de stratégie

Je travaille sur un produit dans lequel la responsabilité de l'un des modules est d'analyser les fichiers XML et de vider le contenu requis dans une base de données. Même si la présente exigence consiste uniquement à analyser des fichiers XML, je souhaite concevoir mon module d'analyse de manière à pouvoir prendre en charge tout type de fichiers à l'avenir. La raison de cette approche est que nous construisons ce produit pour un client spécifique mais prévoyons de le vendre à d'autres clients dans un proche avenir. Tous les systèmes de l'écosystème pour le client actuel produisent et consomment des fichiers XML mais cela peut ne pas être le cas pour d'autres clients.

Qu'est-ce que j'ai essayé jusqu'à présent? (The Present) J'ai le design suivant à l'esprit qui est basé sur le modèle de stratégie. J'ai rapidement écrit le code dans Eclipse pour transmettre ma conception, donc ce serait génial si d'autres aspects tels que la bonne façon de gérer les exceptions étaient ignorés pour l'instant.

Parser: L'interface de stratégie qui expose une méthode d'analyse.

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

* La raison d'utiliser un paramètre générique est d'autoriser tout type de retour et d'assurer la sécurité du type au moment de la compilation.

ProductDataXmlParser Une classe concrète pour analyser un fichier product.xml qui contient des informations relatives au produit. (en utilisant XMLBeans)

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 et ProductDataDocument sont des classes POJO XMlBean générées à l'aide d'un xsd et de la commande scomp.

L'avenir

Si j'ai un fichier product.txt à analyser à l'avenir, je peux définir mon propre POJO appelé ProductData qui contiendra le contenu requis du fichier. Je peux ensuite créer une classe concrète appelée ProductDataFlatFileParser qui implémente l'interface Parser et demander à la méthode d'analyse de remplir le ProductData POJO pour moi après avoir analysé le fichier.

Cette conception a-t-elle un sens? Y a-t-il des défauts évidents dans cette conception? Dans l'état actuel de la conception, j'autorise les classes concrètes à définir l'algorithme pour analyser un fichier et laisse la classe concrète décider où remplir les données. La conception semble être plus dépendante des objets de domaine plutôt que des formats de fichiers. Est-ce une mauvaise chose? Toute contribution sur la façon dont je peux améliorer ma conception sera très appréciée.

14
CKing

J'ai quelques inquiétudes:

  1. Je m'assurerais que vous ayez réellement besoin d'une conception générique avant de l'implémenter. Voulez-vous vraiment avoir besoin de types de fichiers autres que XML? Sinon, pourquoi coder pour eux? Si vous en avez finalement besoin, vous pouvez adapter votre code à ce stade. Cela ne prendra pas beaucoup plus de temps, vous aurez probablement d'autres exigences qui rendront le code différent de ce que vous proposez actuellement, et vous n'aurez probablement jamais besoin de l'écrire de toute façon. Comme on dit, YAGNI (vous n'en aurez pas besoin).
  2. Si vous avez réellement besoin d'une conception générique et que vous en êtes certain, je dirais que Parser<T> est fondamentalement solide. Je vois deux problèmes potentiels: (1) il suppose une entrée de fichier - que faire si vous essayez d'analyser un flux JSON que vous avez récupéré d'une réponse HTTP, par exemple? et (2) il ne fournit pas nécessairement beaucoup de valeur, sauf dans le cadre d'un cadre générique plus large où vous avez beaucoup de différents types d'analyseurs pour de nombreux types de données différents. Mais je ne suis pas convaincu que vous ayez besoin d'un tel grand cadre générique. Vous avez juste un cas d'utilisation très simple et concret pour autant que je sache: analyser un fichier XML dans une liste de ProductDatas.
  3. Ce n'est presque jamais une bonne idée d'avaler des exceptions comme vous le faites dans ProductDataXmlParser. Je le convertirais plutôt en une sorte de RuntimeException.
7
Eric Galluzzo

Votre conception n'est pas une meilleure option. Par votre conception, la seule façon de l'utiliser:

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

Nous ne pouvons pas voir trop d'avantages de l'exemple ci-dessus. Nous ne pouvons pas faire des choses comme ça:

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

Vous pouvez envisager les deux options suivantes avant de rechercher le générique:

  • 1, même sortie après analyse

Quelle que soit la provenance de la source de données, les données du produit seront au même format avant de les enregistrer dans la base de données. C'est le contrat entre le client et votre service de vidage. Je suppose donc que vous avez les mêmes ProductData en sortie. Vous pouvez simplement définir une interface:

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

De plus, vous définissez ProductData comme interface si vous le souhaitez plus flexible.

Si vous ne voulez pas que l'analyseur soit mélangé avec les données. Vous pouvez le diviser en deux interfaces:

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

Et votre analyseur ressemblera à ceci:

public class XMLParser implements Parser, Data {} 
public class TextParser implements Parser, Data {}
  • 2, sortie différente après l'analyse

Si le ProductData n'est pas similaire et que vous souhaitez réutiliser l'interface Parser. Vous pouvez le faire de cette façon:

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();        
}
1
Canhua Li