การแยกวิเคราะห์ไฟล์ทั่วไปใน Java โดยใช้รูปแบบกลยุทธ์


14

ฉันกำลังทำงานกับผลิตภัณฑ์ที่ความรับผิดชอบของหนึ่งในโมดูลคือการแยกวิเคราะห์ไฟล์ XML และถ่ายโอนเนื้อหาที่ต้องการในฐานข้อมูล แม้ว่าความต้องการในปัจจุบันจะเป็นเพียงการแยกวิเคราะห์ไฟล์ XML แต่ฉันต้องการออกแบบโมดูลการแยกวิเคราะห์ในแบบที่ฉันสามารถรองรับไฟล์ประเภทใดก็ได้ในอนาคต เหตุผลสำหรับวิธีนี้คือเรากำลังสร้างผลิตภัณฑ์นี้สำหรับลูกค้าเฉพาะ แต่วางแผนที่จะขายให้กับลูกค้ารายอื่นในอนาคตอันใกล้ ระบบทั้งหมดในระบบนิเวศสำหรับลูกค้าปัจจุบันผลิตและใช้ไฟล์ XML แต่นี่อาจไม่เป็นกรณีสำหรับลูกค้ารายอื่น

ฉันพยายามทำอะไรจนถึงตอนนี้? (ปัจจุบัน) ฉันมีการออกแบบต่อไปนี้ในใจซึ่งขึ้นอยู่กับรูปแบบกลยุทธ์ ฉันได้เขียนรหัสลงในคราสอย่างรวดเร็วเพื่อถ่ายทอดการออกแบบของฉันดังนั้นมันจะดีมากหากแง่มุมอื่น ๆ เช่นวิธีการที่เหมาะสมในการจัดการข้อยกเว้นถูกละเว้นในตอนนี้

Parser:อินเตอร์เฟสกลยุทธ์ที่แสดงเมธอดการวิเคราะห์

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

* เหตุผลในการใช้พารามิเตอร์ทั่วไปคืออนุญาตประเภทการส่งคืนใด ๆ รวมถึงความปลอดภัยของประเภทในเวลารวบรวม

ProductDataXmlParserคลาสที่เป็นรูปธรรมสำหรับการวิเคราะห์ไฟล์ product.xml ที่มีข้อมูลที่เกี่ยวข้องกับผลิตภัณฑ์ (ใช้ 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 และ ProductDataDocument เป็นคลาส XMlBean POJO ที่สร้างขึ้นโดยใช้คำสั่ง xsd และ scomp

อนาคต

ถ้าฉันมีไฟล์ product.txt ที่จะแยกวิเคราะห์ในอนาคตฉันสามารถกำหนด POJO ของตัวเองชื่อ ProductData ที่จะเก็บเนื้อหาที่ต้องการของไฟล์ จากนั้นฉันสามารถสร้างคลาสคอนกรีตที่ชื่อว่า ProductDataFlatFileParser ซึ่งใช้อินเตอร์เฟส Parser และมีวิธีการแยกวิเคราะห์ซึ่งจะเติม ProductData POJO ให้ฉันหลังจากการแยกไฟล์

การออกแบบนี้สมเหตุสมผลหรือไม่ มีข้อบกพร่องที่ชัดเจนในการออกแบบนี้หรือไม่? ขณะที่การออกแบบย่อมาจากนี้ฉันอนุญาตให้คลาสคอนกรีตเพื่อกำหนดอัลกอริทึมในการแยกวิเคราะห์ไฟล์และให้คลาสคอนกรีตตัดสินใจว่าจะเก็บข้อมูลที่ใด การออกแบบดูเหมือนจะขึ้นอยู่กับวัตถุโดเมนมากกว่ารูปแบบไฟล์ นี่เป็นสิ่งที่ไม่ดีหรือไม่? ข้อมูลใด ๆ เกี่ยวกับวิธีที่ฉันสามารถปรับปรุงการออกแบบของฉันจะได้รับการชื่นชมอย่างมาก


ซอฟต์แวร์ควรไม่ให้ผู้โทรทราบหรือไม่ว่ารูปแบบไฟล์รองรับอะไรบ้าง? ซอฟต์แวร์ของคุณทราบได้อย่างไรว่าโปรแกรมแยกวิเคราะห์ตัวใดที่จะเรียกใช้
tomdemuyt

คุณกำลังมองหาข้อเสนอแนะเกี่ยวกับการออกแบบของคุณไม่ใช่การใช้งานจริงของคุณดังนั้นสิ่งนี้จะถูกย้ายไปยังโปรแกรมเมอร์ที่อยู่ในหัวข้อ
codesparkle

@tomdemuyt คิดแบบโรงงาน;)
CKing

2
@bot ผู้ใช้ SO ที่บอกให้คุณโพสต์สิ่งนี้บน Code Review นั้นผิดอย่างเห็นได้ชัด คุณสามารถอ่านคำถามที่พบบ่อยของเว็บไซต์ก่อนโพสต์ "มีคนบอกให้ฉันทำ" ไม่ใช่เหตุผลที่ดีที่คุณจะทำอะไร ไม่มีใครเล่นปิงปองด้วยมีคนอาสาเวลาและพยายามหาที่ที่ดีกว่าแทนการปิดทันที (ซึ่งน่าจะเป็นตัวเลือกที่ถูกต้อง
yannis

2
กรุณาอย่าขวางทางเช่นกัน คุณกำลังยุ่งเราต้องทำความสะอาด
ฉีกออก

คำตอบ:


7

ฉันมีข้อกังวลสองสามข้อ:

  1. ฉันจะทำให้แน่ใจว่าคุณต้องการการออกแบบทั่วไปก่อนที่จะนำไปใช้ คุณแน่ใจหรือว่าต้องการไฟล์ประเภทอื่นที่ไม่ใช่ XML ถ้าไม่ทำไมรหัสสำหรับพวกเขา หากคุณต้องการใช้ในที่สุดคุณสามารถติดตั้งรหัสของคุณใหม่ได้ ณ จุดนั้น ใช้เวลาไม่นานนักคุณอาจมีข้อกำหนดอื่น ๆ ที่จะทำให้โค้ดดูแตกต่างจากที่คุณเสนอในปัจจุบันและคุณอาจไม่จำเป็นต้องเขียนมันเลย ตามที่พวกเขาพูด YAGNI (คุณไม่ต้องการมัน)
  2. หากคุณต้องการการออกแบบทั่วไปและคุณค่อนข้างแน่ใจในเรื่องนี้ฉันจะบอกว่าParser<T>มันฟังดูดี ฉันเห็นปัญหาที่อาจเกิดขึ้นสองประการ: (1) สมมติว่าอินพุตไฟล์ - ถ้าคุณพยายามแยกสตรีม JSON ที่คุณดึงจากการตอบกลับ HTTP มาเป็นตัวอย่าง และ (2) ไม่จำเป็นต้องให้คุณค่ามากนักยกเว้นเป็นส่วนหนึ่งของกรอบทั่วไปที่มีขนาดใหญ่กว่าซึ่งคุณมีตัวแยกวิเคราะห์หลายประเภทสำหรับข้อมูลประเภทต่าง ๆ มากมาย แต่ฉันไม่มั่นใจว่าคุณต้องการกรอบทั่วไปขนาดใหญ่เช่นนี้ คุณเพียงแค่มีความง่ายมากกรณีการใช้งานที่เป็นรูปธรรมในขณะนี้เท่าที่ผมสามารถบอกได้: แยกไฟล์ XML ลงในรายการของProductDatas
  3. ProductDataXmlParserมันเกือบจะไม่เคยมีความคิดที่ดีที่จะกลืนข้อยกเว้นในขณะที่คุณกำลังทำอยู่ใน ฉันจะแปลงเป็นบางประเภทRuntimeExceptionแทน

1
เรากำลังสร้างผลิตภัณฑ์ที่จะสื่อสารกับระบบภายนอกจำนวนมากดังนั้นฉันคิดว่ามันเป็นความคิดที่ดีที่จะพิจารณารูปแบบไฟล์ / อินพุตใด ๆ จุดที่ยอดเยี่ยมเกี่ยวกับ JSON Stream นั่นคือเหตุผลที่ฉันมีวิธีการแยกวิเคราะห์ของฉันในส่วนติดต่อ Parser ใช้พารามิเตอร์ String แทนพารามิเตอร์ File ฉันมีข้อผิดพลาดเล็กน้อยใน ProductDataXmlParser ซึ่งฉันได้แก้ไข (ต้องส่งไฟล์ไปที่ตัวแยกวิเคราะห์ XmlBean) คุณยังถูกต้องเกี่ยวกับการกลืนข้อยกเว้น ผมเขียนลงรหัสนี้ได้อย่างรวดเร็วในคราสในการถ่ายทอดการออกแบบของฉันใน StackOverflow ผ่านตัวอย่าง;)
cking

โอเคดี. ฉันเดาว่าฉันจะทำให้พารามิเตอร์ Parser เป็น InputStream แทนที่จะเป็น String นั่นคือสิ่งที่ฉันพูด :) และดีใจที่ได้ทราบเกี่ยวกับข้อยกเว้น - ฉันไม่แน่ใจว่าถูกตัดแล้ววางจากรหัสจริงของคุณหรือเพียงแค่โค้ดตัวอย่างสำหรับ StackOverflow

1
เกี่ยวกับการสร้างผลิตภัณฑ์ที่จะสื่อสารกับระบบภายนอกจำนวนมากฉันลังเลที่จะสร้างรหัสทั่วไปโดยไม่ต้องมีรูปธรรม ตัวอย่างเช่นจนกว่าคุณจะมีอย่างน้อยสองชนิดของวัตถุที่จะแยกวิเคราะห์หรือสองรูปแบบไฟล์ที่คุณต้องการฉันจะไม่ทำอินเทอร์เฟซ Parser ทั่วไป

ฉันจะให้ความคิดกับสิ่งที่คุณพูด ฉันอยากจะชี้ให้เห็นว่ามีไฟล์ xml ที่แตกต่างกัน 4 ไฟล์ที่มีการแยกวิเคราะห์ข้อมูล 4 ประเภท ข้อมูลผลิตภัณฑ์เป็นเพียงข้อมูลประเภทเดียวที่ระบบ / ผลิตภัณฑ์ของเราใช้
CKing

ฉันมีคำถามอีกหนึ่งข้อสำหรับคุณ ฉันจะไม่ใช้บริบทที่เป็นส่วนหนึ่งของรูปแบบกลยุทธ์ มันจะไม่เป็นไร ฉันกำลังกำจัดพารามิเตอร์ทั่วไปและส่งคืน Object ในวิธีวิเคราะห์คำในอินเทอร์เฟซ Parser นี่คือการหลีกเลี่ยงคลาสที่ใช้ Parser เพื่อประกาศด้วยพารามิเตอร์ type
CKing

1

การออกแบบของคุณไม่ใช่ตัวเลือกที่ดีที่สุด จากการออกแบบของคุณวิธีเดียวที่จะใช้:

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

เราไม่เห็นประโยชน์มากเกินไปจากตัวอย่างด้านบน เราทำสิ่งนี้ไม่ได้:

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

คุณสามารถพิจารณาสองตัวเลือกต่อไปนี้ก่อนที่จะค้นหาทั่วไป:

  • 1, เอาต์พุตเดียวกันหลังจากวิเคราะห์คำ

ไม่ว่าแหล่งข้อมูลจะมาจากที่ไหนข้อมูลของผลิตภัณฑ์จะเป็นรูปแบบเดียวกันก่อนที่คุณจะบันทึกลงในฐานข้อมูล เป็นสัญญาระหว่างลูกค้ากับบริการถ่ายโอนข้อมูลของคุณ ดังนั้นฉันสมมติว่าคุณมี ProductData เหมือนกับเอาต์พุต คุณสามารถกำหนดอินเตอร์เฟส:

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

ยิ่งกว่านั้นคุณยังกำหนด ProductData เป็นอินเทอร์เฟซถ้าคุณต้องการความยืดหยุ่น

หากคุณไม่ต้องการให้ Parser ผสมกับข้อมูล คุณสามารถแยกมันเป็นสองอินเตอร์เฟส:

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

ในกรณีที่คุณต้องการใช้สิ่งที่มีอยู่แล้วฉันได้สร้างไลบรารี java ขึ้นมาแล้ว JRecordBindซึ่งใช้ XMLSchema (สำรองโดย JAXB)

มันเกิดมาเพื่อใช้ / สร้างไฟล์ความยาวคงที่และเนื่องจาก XMLSchema กำหนดโครงสร้างของไฟล์คุณสามารถใช้กับ JAXB ธรรมดาเพื่อ marshall / unmarshall XML ไฟล์


ฉันกำลังมองหาการออกแบบเพื่อใช้ตัวแยกวิเคราะห์ทั่วไป! ผมไม่คิดว่าคุณ uderstood คำถามของฉันได้อย่างถูกต้อง. :)
cking
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.