Ogólny projekt parsera plików w Javie przy użyciu wzorca strategii

14

Pracuję nad produktem, w którym jednym z modułów jest parsowanie plików XML i zrzucanie wymaganej zawartości do bazy danych. Mimo że obecnym wymaganiem jest tylko parsowanie plików XML, chcę zaprojektować mój moduł analizujący w taki sposób, aby w przyszłości mógł obsługiwać dowolny rodzaj plików. Powodem takiego podejścia jest to, że budujemy ten produkt dla konkretnego klienta, ale planujemy sprzedać go innym klientom w najbliższej przyszłości. Wszystkie systemy w ekosystemie dla bieżącego klienta wytwarzają i zużywają pliki XML, ale może nie być tak w przypadku innych klientów.

Co do tej pory próbowałem? (Teraźniejszość) Mam na myśli następujący projekt oparty na schemacie strategii. Szybko napisałem kod w eclipse, aby przekazać mój projekt, więc byłoby wspaniale, gdyby inne aspekty, takie jak właściwy sposób obsługi wyjątków, były na razie ignorowane.

Analizator składni : interfejs strategii udostępniający metodę analizy składni.

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

* Powodem użycia parametru ogólnego jest umożliwienie dowolnego typu zwrotu, a także zapewnienie bezpieczeństwa typu w czasie kompilacji.

ProductDataXmlParser Konkretna klasa do analizowania pliku product.xml, który zawiera informacje związane z produktem. (przy użyciu 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();
    }
} 

gdzie : ProductDataTYPE i ProductDataDocument to klasy POJO XMlBean wygenerowane za pomocą polecenia xsd i polecenia scomp.

Przyszłość

Jeśli mam plik product.txt do przeanalizowania w przyszłości, mogę zdefiniować własne POJO o nazwie ProductData, które będzie przechowywać wymaganą zawartość pliku. Następnie mogę utworzyć konkretną klasę o nazwie ProductDataFlatFileFarParser, która implementuje interfejs Parsera, a metoda parsowania wypełnia dla mnie POJO produktu ProductData po przeanalizowaniu pliku.

Czy ten projekt ma sens? Czy są jakieś oczywiste wady w tym projekcie? Na obecnym etapie pozwalam konkretnym klasom zdefiniować algorytm do parsowania pliku, a konkretna klasa decyduje, gdzie wypełnić dane. Wygląda na to, że projekt bardziej zależy od obiektów domeny niż formatów plików. Czy to źle? Wszelkie uwagi dotyczące ulepszenia mojego projektu będą bardzo mile widziane.

CKing
źródło
Czy oprogramowanie nie powinno informować dzwoniącego o obsługiwanych formatach plików? Skąd twoje oprogramowanie wie, który parser wywołać?
tomdemuyt
Szukasz opinii na temat swojego projektu , a nie faktycznej implementacji , więc zostanie on przeniesiony do programistów tam, gdzie jest na dany temat.
codesparkle
@tomdemuyt Pomyśl wzór fabryczny;)
CKing
2
@bot Użytkownik SO, który kazał Ci opublikować to w recenzji kodu, był oczywiście w błędzie. Możesz przeczytać często zadawane pytania na stronie, zanim je opublikujesz, „ktoś mi kazał to zrobić” nie jest tak naprawdę dobrym powodem do zrobienia czegokolwiek. Nikt nie gra w ping ponga, ktoś zgłosił się na ochotnika i starał się znaleźć lepsze miejsce zamiast go całkowicie zamknąć (co byłoby dobrą opcją, ponieważ nie jest to tematem recenzji kodu).
yannis
2
Proszę też nie krzyżować. Robisz bałagan, który musimy posprzątać.
Zerwano

Odpowiedzi:

7

Mam kilka obaw:

  1. Upewnij się, że naprawdę potrzebujesz ogólnego projektu przed jego wdrożeniem. Czy na pewno będziesz potrzebować typów plików innych niż XML? Jeśli nie, to po co dla nich kodować? Jeśli w końcu będziesz go potrzebować, możesz w tym momencie zmodernizować kod. To nie potrwa długo, prawdopodobnie będziesz mieć inne wymagania, które sprawią, że kod będzie wyglądał inaczej niż obecnie proponujesz i prawdopodobnie nigdy nie będziesz musiał go pisać. Jak mówią, YAGNI (You Bein Go Need Need It).
  2. Jeśli naprawdę potrzebujesz ogólnego projektu i jesteś tego całkiem pewien, powiedziałbym, że Parser<T>to w zasadzie dobry dźwięk. Widzę dwa potencjalne problemy: (1) zakłada, że ​​dane wejściowe do pliku - na przykład, jeśli próbujesz przeanalizować strumień JSON pobrany z odpowiedzi HTTP? i (2) niekoniecznie zapewnia dużą wartość, z wyjątkiem części większego ogólnego środowiska, w którym masz wiele różnych typów parserów dla wielu różnych typów danych. Ale nie jestem przekonany, że potrzebujesz tak dużych ogólnych ram. Po prostu masz teraz bardzo prosty, konkretny przypadek użycia, o ile mogę powiedzieć: parsuj plik XML na listę ProductDatas.
  3. Prawie nigdy nie jest dobrym pomysłem przełykanie wyjątków podczas pracy ProductDataXmlParser. RuntimeExceptionZamiast tego przekonwertowałbym go na jakiś .

źródło
1
Budujemy produkt, który będzie komunikował się z wieloma systemami zewnętrznymi, więc myślę, że dobrym pomysłem byłoby uwzględnienie dowolnego rodzaju pliku / formatu wejściowego. Doskonały punkt na temat strumienia JSON. Właśnie dlatego kazałem mojej metodzie parsowania w interfejsie Parsera wziąć parametr String zamiast parametru File. Miałem niewielki błąd w moim ProductDataXmlParser, który poprawiłem (muszę przekazać plik do parsera XmlBean). Masz również rację co do połykania wyjątków.
Zapisałem
Ok fajnie. Myślę, że ustawiłbym parametr Parser jako InputStream zamiast String, tak mówię. :) I dobrze słyszeć o wyjątku - nie byłem pewien, czy został on wycięty i wklejony z twojego kodu, czy tylko przykładowy kod dla StackOverflow.
1
Ponadto, jeśli chodzi o budowę produktu, który będzie komunikował się z wieloma systemami zewnętrznymi, zawahałbym się zbudować ogólny kod bez konkretnych wymagań. Na przykład, dopóki nie będziesz mieć co najmniej dwóch typów obiektów do parsowania lub dwóch formatów plików, których potrzebujesz, nie stworzyłbym ogólnego interfejsu Parsera.
Zastanowię się nad tym, co mówisz. Chciałbym zaznaczyć, że istnieją 4 różne pliki xml zawierające 4 różne typy danych do przeanalizowania. Dane produktu to tylko jeden rodzaj danych, które mają być wykorzystywane przez nasz system / produkt.
CKing
Mam do ciebie jeszcze jedno pytanie. Nie zamierzam używać kontekstu, który jest częścią wzorca strategii. Czy to będzie w porządku? Pozbywam się również ogólnych parametrów i zwracam Object w metodzie parsowania w interfejsie Parsera. Ma to na celu uniknięcie deklarowania klas, które używają parsera do zadeklarowania za pomocą parametru typu.
CKing
1

Twój projekt nie jest najlepszą opcją. Według twojego projektu jedyny sposób, aby go użyć:

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

Z powyższego przykładu nie widzimy zbyt dużych korzyści. Nie możemy robić takich rzeczy:

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

Zanim zaczniesz szukać ogólnego, możesz rozważyć następujące dwie opcje:

  • 1, To samo wyjście po analizie

Bez względu na to, skąd pochodzi źródło danych, dane produktu będą miały ten sam format przed zapisaniem ich w bazie danych. Jest to umowa między klientem a usługą zrzutu. Zakładam, że masz te same dane produktu co dane wyjściowe. Możesz po prostu zdefiniować interfejs:

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

Ponadto definiujesz ProductData jako interfejs, jeśli chcesz, aby był bardziej elastyczny.

Jeśli nie chcesz, aby parser był mieszany z danymi. Możesz podzielić go na dwa interfejsy:

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

Twój parser będzie wyglądał następująco:

public class XMLParser implements Parser, Data {} 
public class TextParser implements Parser, Data {}
  • 2, różne dane wyjściowe po analizie

Jeśli dane produktu nie są podobne i chcesz ponownie użyć interfejsu analizatora składni. Możesz to zrobić w ten sposób:

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
źródło
-2

Na wypadek, gdybyś wolał użyć czegoś już dostępnego, stworzyłem bibliotekę Java o nazwie JRecordBind opartą na XMLSchema (wspieranej przez JAXB).

Urodził się, aby konsumować / produkować pliki o stałej długości, a ponieważ XMLSchema definiuje ich strukturę, możesz używać go ze zwykłym JAXB do marshall / unmarshall plików XML

Federico Fissore
źródło
Szukam projektu do wdrożenia ogólnego parsera! Nie sądzę, że dobrze zrozumiałeś moje pytanie :)
CKing