Design genérico do analisador de arquivos em Java usando o padrão Strategy

14

Estou trabalhando em um produto no qual a responsabilidade de um dos módulos é analisar arquivos XML e despejar o conteúdo necessário em um banco de dados. Mesmo que o requisito atual seja apenas analisar arquivos XML, desejo projetar meu módulo de análise de forma que possa suportar qualquer tipo de arquivo no futuro. O motivo dessa abordagem é que estamos construindo este produto para um cliente específico, mas planejamos vendê-lo para outros clientes em um futuro próximo. Todos os sistemas no ecossistema para o cliente atual produzem e consomem arquivos XML, mas isso pode não ser o caso para outros clientes.

O que eu tentei até agora? (O presente) Tenho em mente o seguinte design, baseado no padrão de estratégia. Eu rapidamente escrevi o código no eclipse para transmitir meu design, então seria ótimo se outros aspectos, como a maneira correta de lidar com exceções, fossem ignorados por enquanto.

Analisador: a interface da estratégia que expõe um método de análise.

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

* O motivo do uso de um parâmetro genérico é permitir qualquer tipo de retorno e garantir a segurança do tipo no momento da compilação.

ProductDataXmlParser Uma classe concreta para analisar um arquivo product.xml que contém informações relacionadas ao produto. (usando 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();
    }
} 

em que : ProductDataTYPE e ProductDataDocument são classes XMlBean POJO geradas usando um xsd e o comando scomp.

O futuro

Se eu tiver um arquivo product.txt a ser analisado no futuro, posso definir meu próprio POJO chamado ProductData que conterá o conteúdo necessário do arquivo. Em seguida, posso criar uma classe concreta chamada ProductDataFlatFileParser que implementa a interface Parser e fazer com que o método de análise preencha o POJO ProductData para mim depois de analisar o arquivo.

Esse design faz sentido? Existem falhas óbvias nesse design? Como está o design, estou permitindo que as classes concretas definam o algoritmo para analisar um arquivo e deixe a classe concreta decidir onde preencher os dados. O design parece ser mais dependente dos objetos do domínio do que dos formatos de arquivo. Isso é ruim? Quaisquer contribuições sobre como melhorar meu design serão muito apreciadas.

CKing
fonte
O software não deve deixar o chamador saber quais formatos de arquivo são suportados? Como o seu software sabe qual analisador chamar?
22613 Tomdemuyt
Você está procurando feedback sobre seu design , não sua implementação real , portanto, isso será migrado para os programadores, onde está o tópico.
codesparkle
@tomdemuyt Pense no padrão de fábrica;)
CKing
2
@bot O usuário de SO que pediu para você postar isso na Code Review estava obviamente errado. Você poderia ter lido as Perguntas frequentes do site antes de publicá-las, "alguém me disse para fazê-lo" não é realmente um bom motivo para você fazer alguma coisa. Ninguém joga pingue-pongue com ele, alguém ofereceu seu tempo e tentou descobrir um lugar melhor para ele em vez de fechá-lo completamente (o que teria sido uma opção válida, pois é um tópico fora do Code Review).
yannis
2
Por favor, não cruze também. Você está fazendo uma bagunça que precisamos limpar.
Arrancado em

Respostas:

7

Tenho algumas preocupações:

  1. Eu garantiria que você realmente precisasse de um design genérico antes de implementá-lo. Tem certeza de que precisará de outros tipos de arquivo que não XML? Se não, por que codificar para eles? Se, eventualmente, você precisar, poderá atualizar seu código nesse momento. Não demorará muito mais, você provavelmente terá outros requisitos que farão com que o código pareça diferente do que você está propondo atualmente e provavelmente nunca precisará escrevê-lo. Como se costuma dizer, YAGNI (você não vai precisar disso).
  2. Se você realmente precisa de um design genérico e tem certeza disso, então eu diria que Parser<T>é basicamente bom. Eu vejo dois problemas em potencial: (1) ele assume a entrada do arquivo - e se você estiver tentando analisar um fluxo JSON recuperado de uma resposta HTTP, por exemplo? e (2) não necessariamente fornece muito valor, exceto como parte de uma estrutura genérica maior, na qual você tem muitos tipos diferentes de analisadores para muitos tipos diferentes de dados. Mas não estou convencido de que você precise de uma estrutura genérica tão grande. Você apenas tem um caso de uso concreto muito simples agora, tanto quanto posso dizer: analise um arquivo XML em uma lista de ProductDatas.
  3. Quase nunca é uma boa idéia engolir exceções como você está fazendo ProductDataXmlParser. Eu o converteria para algum tipo de RuntimeExceptionalternativa.

fonte
1
Estamos construindo um produto que se comunicará com muitos sistemas externos, então acho que seria uma boa ideia dar conta de qualquer tipo de formato de arquivo / entrada. Excelente ponto sobre o fluxo JSON. É exatamente por isso que meu método de análise na interface Parser usa um parâmetro String em vez de um parâmetro File. Cometi um pequeno erro no meu ProductDataXmlParser que corrigi (é necessário passar um arquivo para o analisador XmlBean). Você também está certo sobre engolir exceções. Eu escrevi esse código rapidamente no eclipse para transmitir meu design no StackOverflow através de um exemplo;) #
22413
OK legal. Eu acho que eu faria o parâmetro Parser um InputStream em vez de um String, é o que estou dizendo. :) E bom ouvir sobre a exceção - eu não tinha certeza se isso foi recortado e colado no seu código real ou apenas um exemplo de código para o StackOverflow.
1
Além disso, em relação à construção de um produto que se comunicará com muitos sistemas externos, hesitaria em criar qualquer código genérico sem requisitos concretos. Por exemplo, até que você tenha pelo menos dois tipos de objetos para analisar ou dois formatos de arquivo necessários, eu não criaria uma interface Parser genérica.
Vou pensar no que você está dizendo. Gostaria de salientar que existem 4 arquivos xml diferentes contendo 4 tipos diferentes de dados a serem analisados. Os dados do produto são apenas um tipo de dados a serem consumidos pelo nosso sistema / produto.
19413 CKing
Eu tenho mais uma pergunta para você. Não vou usar um contexto que faça parte do padrão de estratégia. Vai ficar tudo bem? Também estou me livrando dos parâmetros genéricos e retornando Object no método de análise na interface Parser. Isso evita que as classes que usam o analisador sejam declaradas com um parâmetro de tipo.
CKING
1

Seu design não é a melhor opção. Pelo seu design, a única maneira de usá-lo:

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

Não podemos ver muitos benefícios do exemplo acima. Não podemos fazer coisas assim:

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

Você pode considerar as duas opções a seguir antes de procurar o genérico:

  • 1, mesma saída após análise

Independentemente da origem da fonte de dados, os dados do produto terão o mesmo formato antes de salvá-los no banco de dados. É o contrato entre o cliente e seu serviço de despejo. Então, suponho que você tenha o mesmo ProductData da saída. Você pode simplesmente definir uma interface:

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

Além disso, você define ProductData como interface, se quiser mais flexível.

Se você não deseja que o Analisador seja misturado com os dados. Você pode dividi-lo em duas interfaces:

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

E seu analisador ficará assim:

public class XMLParser implements Parser, Data {} 
public class TextParser implements Parser, Data {}
  • 2, saída diferente após a análise

Se o ProductData não for semelhante e você desejar reutilizar a interface do Parser. Você pode fazer assim:

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

Apenas no caso de você preferir usar algo já disponível, eu fiz uma biblioteca java chamado JRecordBind que é baseada em XMLSchema (apoiado por JAXB).

Nasceu para consumir / produzir arquivos de tamanho fixo e, como o XMLSchema define sua estrutura, você pode usá-lo com JAXB simples para ordenar / desmarcar arquivos XML

Federico Fissore
fonte
Estou procurando um design para implementar um analisador genérico! Eu não acho que você uderstood minha pergunta corretamente :).
cking