Strateji kalıbını kullanarak Java'da genel dosya ayrıştırıcı tasarımı


14

Modüllerden birinin sorumluluğunun XML dosyalarını ayrıştırmak ve gerekli içeriği bir veritabanına dökmek olduğu bir ürün üzerinde çalışıyorum. Mevcut gereksinim yalnızca XML dosyalarını ayrıştırmak olsa da, ayrıştırma modülümü gelecekte her türlü dosyayı destekleyebileceğim şekilde tasarlamak istiyorum. Bu yaklaşımın nedeni, bu ürünü belirli bir müşteri için inşa etmemiz, ancak yakın gelecekte diğer müşterilere satmayı planlamamızdır. Mevcut istemci için ekosistemdeki tüm sistemler XML dosyaları üretir ve tüketir, ancak bu diğer istemciler için geçerli olmayabilir.

Şimdiye kadar ne denedim? (Günümüz) Strateji modeline dayanan şu tasarıma sahibim. Tasarımımı iletmek için tutulma kodunu hızlı bir şekilde yazdım, bu nedenle istisnaları ele alma gibi uygun yönler şimdilik göz ardı edilirse harika olurdu.

Ayrıştırıcı: Bir ayrıştırma yöntemini ortaya koyan strateji arabirimi.

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

* Genel bir parametre kullanmanın nedeni, herhangi bir dönüş türüne izin vermek ve derleme zamanında tür güvenliğini sağlamaktır.

ProductDataXmlParser Ürünle ilgili bilgileri içeren bir product.xml dosyasını ayrıştırmak için somut bir sınıf. (XMLBeans kullanarak)

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

burada : ProductDataTYPE ve ProductDataDocument, xsd ve scomp komutu kullanılarak oluşturulan XMlBean POJO sınıflarıdır.

Gelecek

Gelecekte ayrıştırılacak bir product.txt dosyası varsa, dosyanın gerekli içeriğini tutacak ProductData adlı kendi POJO'mu tanımlayabilirim. Daha sonra Parser arabirimini uygulayan ve ayrıştırma yöntemi ProductData POJO benim için dosyayı ayrıştırdıktan sonra doldurmak var ProductDataFlatFileParser adlı somut bir sınıf oluşturabilirsiniz.

Bu tasarım mantıklı mı? Bu tasarımda belirgin kusurlar var mı? Tasarım ayakta dururken, somut sınıfların bir dosyayı ayrıştırmak için algoritmayı tanımlamasına ve somut sınıfın verileri nereye dolduracağına karar vermesine izin veriyorum. Tasarım, dosya biçimlerinden ziyade etki alanı nesnelerine daha bağımlı görünmektedir. Bu kötü bir şey mi? Tasarımımı nasıl geliştirebileceğime dair herhangi bir girdi çok takdir edilecektir.


Yazılım, arayanın hangi dosya biçimlerinin desteklendiğini bilmesine izin vermemeli mi? Yazılımınız hangi ayrıştırıcıyı çağırmayı nasıl biliyor?
tomdemuyt

Tasarımınız hakkında geri bildirim almak istiyorsunuz , gerçek uygulamanız değil , bu konuya konu olan Programcılara taşınacak.
codesparkle

@tomdemuyt Think Factory pattern;)
CKing

2
@ Bot Kod İncelemesinde bunu göndermenizi söyleyen SO kullanıcısı açıkça yanlıştı. Sitenin SSS'sini göndermeden önce okuyabilirsiniz, "birisi bunu yapmamı söyledi", hiçbir şey yapmanıza gerçekten iyi bir neden değil. Kimse onunla ping pong çalmıyor, biri zamanını gönüllü hale getirdi ve bunun yerine tam olarak kapatmak yerine daha iyi bir yer bulmaya çalıştı (Kod İncelemesi için konu dışı olduğu için geçerli bir seçenek olurdu).
yannis

2
Lütfen çapraz postalama da değil. Temizlememiz gereken bir karmaşa yapıyorsunuz.
Off Rip

Yanıtlar:


7

Birkaç endişem var:

  1. Birini uygulamadan önce gerçekten genel bir tasarıma ihtiyacınız olduğundan emin olurum. XML dışında dosya türlerine ihtiyacınız olduğundan emin misiniz? Değilse, neden onlar için kod yazmalısınız? Sonunda ihtiyacınız olursa, kodunuzu bu noktada güçlendirebilirsiniz. Çok uzun sürmeyecek, muhtemelen kodun şu anda teklif ettiğinizden farklı görünmesini sağlayacak başka gereksinimleriniz olacak ve muhtemelen yine de yazmanız gerekmeyecek. Dedikleri gibi, YAGNI (Buna ihtiyacın olmayacak).
  2. Aslında genel bir tasarıma ihtiyacınız varsa ve bundan oldukça eminseniz Parser<T>, temelde sağlam olduğunu söyleyebilirim . İki olası sorun görüyorum: (1) dosya girdisi varsayar - ya bir HTTP yanıtından aldığınız bir JSON akışını ayrıştırmaya çalışıyorsanız, örneğin? ve (2) birçok farklı veri türü için birçok farklı ayrıştırıcı türünüzün bulunduğu daha büyük genel çerçevenin bir parçası olması dışında çok fazla değer sağlaması gerekmez. Ama böyle büyük bir genel çerçeveye ihtiyacınız olduğuna ikna olmadım. Şimdiye kadar anlayabildiğim kadarıyla çok basit, somut bir kullanım durumunuz var: Bir XML dosyasını ProductDatas listesine ayrıştırın .
  3. İstisnaları yaptığınız gibi yutmak neredeyse hiç iyi bir fikir değildir ProductDataXmlParser. Bunun RuntimeExceptionyerine bir çeşit dönüştürürüm .

1
Birçok harici sistemle iletişim kuracak bir ürün geliştiriyoruz, bu yüzden her türlü dosya / giriş biçimini hesaba katmanın iyi bir fikir olacağını düşünüyorum. JSON Stream hakkında mükemmel bir nokta. Bu yüzden ayrıştırıcı yöntemi benim ayrıştırma yöntemi bir File parametresi yerine bir String parametresi almak vardı. Ben düzeltilmiş benim ProductDataXmlParser küçük bir hata vardı (XmlBean ayrıştırıcıya bir dosya geçmek gerekir). İstisnaları yutma konusunda da haklısınız. Ben bir örnek üzerinden stackoverflow tasarımımı iletmek için tutulma hızlı bir şekilde bu kodu yazdı;)
CKing

Tamam iyi. Ben Parser parametresini bir dize yerine bir InputStream yapmak istiyorum sanırım. :) Ve istisna hakkında duymak güzel - Bu gerçek kod veya sadece StackOverflow için örnek kod yapıştırılmış 'n' kesildi emin değildi.

1
Ayrıca, birçok harici sistemle iletişim kuracak bir ürün inşa etmekle ilgili olarak, somut gereksinimler olmadan herhangi bir genel kod oluşturmaktan çekinmeyin. Örneğin, ayrıştırmak için en az iki tür nesneye veya ihtiyacınız olan iki dosya biçimine sahip olana kadar, genel bir Parser arabirimi oluşturmam.

Söylediklerine bir fikir vereceğim. Ayrıştırılacak 4 farklı veri türü içeren 4 farklı xml dosyası olduğunu belirtmek isterim. Ürün verileri, sistemimiz / ürünümüz tarafından tüketilecek sadece bir veri türüdür.
CKing

Sana bir sorum daha var. Strateji modelinin bir parçası olan bir Bağlam kullanmayacağım. Bu iyi olacak mı? Ayrıca genel parametrelerden kurtulup Parser arabirimindeki ayrıştırma yönteminde Object'i döndürüyorum. Bu, ayrıştırıcıyı kullanan sınıfların bir tür parametresiyle bildirilmesini önlemek içindir.
CKing

1

Tasarımınız en iyi seçenek değil. Tasarımınızla kullanmanın tek yolu:

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

Yukarıdaki örnekten çok fazla fayda göremiyoruz. Böyle şeyler yapamayız:

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

Genel aramadan önce aşağıdaki iki seçeneği göz önünde bulundurun:

  • 1, ayrıştırmadan sonra aynı çıktı

Veri kaynağı nereden olursa olsun, veritabanına kaydetmeden önce ürün verileri aynı biçimde olacaktır. Müşteri ile çöplük servisiniz arasındaki sözleşme. Bu yüzden çıktı ile aynı ProductData olduğunu varsayalım. Sadece bir arayüz tanımlayabilirsiniz:

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

Ayrıca daha esnek olmasını istiyorsanız ProductData'yı arayüz olarak tanımlarsınız.

Ayrıştırıcı'nın verilerle karıştırılmasını istemiyorsanız. İki arayüze bölebilirsiniz:

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

Ayrıştırıcınız şöyle görünecektir:

public class XMLParser implements Parser, Data {} 
public class TextParser implements Parser, Data {}
  • 2, ayrıştırmadan sonra farklı çıktı

ProductData benzer değilse ve Ayrıştırıcı arabirimini yeniden kullanmak istiyorsanız. Bunu şu şekilde yapabilirsiniz:

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

Zaten kullanılabilir bir şey kullanmayı tercih ederseniz , JRecordBind adlı XMLSchema (JAXB tarafından desteklenen) tabanlı bir java kütüphanesi yaptım .

Sabit uzunluktaki dosyaları tüketmek / üretmek için doğdu ve XMLSchema yapılarını tanımladığından, XML dosyalarını sıralamak / çözmek için düz JAXB ile kullanabilirsiniz.


Genel bir ayrıştırıcıyı uygulamak için bir tasarım arıyorum! Sorumu doğru anladığınızı sanmıyorum. :)
CKing
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.