2011-11-29 16 views
9

मेरे पास यह स्थिति है जहां मेरे डेटा के दो सेट के बीच एक मूल शिशु संबंध है। मेरे पास एक मूल दस्तावेज़ संग्रह और एक बाल दस्तावेज़ संग्रह है। आवश्यकता यह है कि माता-पिता और उनके संबंधित बच्चों को 'ए' पीडीएफ दस्तावेज में निर्यात करने की आवश्यकता है।लूप के लिए नेस्टेड रीफैक्टरिंग

for(Document parentDocument:Documents){ 
    ExportToPdf(parentDocument); 
    for(Document childDocument:parentDocument.children()){ 
     AppendToParentPdf(childDocument); 
    } 
} 

कुछ के रूप में ऊपर शायद समस्या का समाधान होगा, लेकिन अचानक आवश्यकताओं में परिवर्तन और के सभी अब इनमें से प्रत्येक: उपरोक्त स्थिति का एक सरल-कार्यान्वयन के रूप में इस प्रकार है (जावा-ish छद्म कोड के नीचे) हो सकता है तो ऊपर दिए गए टुकड़ा बदलते ExportToPdf() को AppendToParentPdf() इस प्रकार से संशोधित किया गया है माता पिता और उनके इसी बच्चों, अलग pdfs में होना चाहिए:

for(Document parentDocument:Documents){ 
    ExportToPdf(parentDocument); 
    for(Document childDocument:parentDocument.children()){ 
     ExportToPdf(childDocument); 
    } 
} 

इस रास्ते में जा रहे हैं, यह लंबे समय के लिए इस प्रतीत होता है तुच्छ स्निपेट के पहले नहीं ले जाएगा होगा कुछ गंभीर कोड गंध से पीड़ित हैं।

मेरे सवालों का इतना कर रहे हैं:

  1. इस तरह के ऊपर के रूप में अभिभावक-बच्चे रिश्तों के बेहतर निरूपण कर रहे हैं, जहां के बजाय जानवर-मजबूर कर सभी दस्तावेजों और एक O(n^2) फैशन में अपने बच्चों के माध्यम से अपने रास्ते, मैं पूरी संरचना को अधिक इष्टतम फैशन में पार करने के लिए एक अलग डेटा-संरचना या तकनीक का उपयोग कर सकता हूं।

  2. परिदृश्य में मैंने ऊपर वर्णित परिदृश्य में, जहां व्यापार नियमों को पीडीएफ निर्यात के तरीके के बारे में तरल पदार्थ है, क्या निर्यात समारोह की प्रकृति को कोड करने का एक बेहतर तरीका है? निर्यात प्रारूप भी क्षणिक है। पीडीएफ * .docs/csvs/xmls et al को रास्ता दे सकता है।

इस पर कुछ परिप्रेक्ष्य प्राप्त करना बहुत अच्छा होगा।

धन्यवाद

+0

अपने पहले प्रश्न का सवाल है, यह देखने के लिए नहीं है की तरह आप के लिए मजबूर जानवर हैं, क्योंकि आप केवल हर माता पिता के लिए parentDocument.Children पुन: प्राप्त करने कर रहे हैं और यह एक विशेष माता-पिता के लिए सभी बच्चों के दस्तावेजों की सूची में शामिल है। तो आपकी समय जटिलता ओ (एन^2) नहीं बल्कि ओ (एन + एम) है जहां एन और एम क्रमशः माता-पिता और बाल दस्तावेजों की गिनती हैं। – Santhosh

+0

@sc_ray आपको यह अवश्य बता देना चाहिए कि 'childDocument' के लिए एक से अधिक 'parentDocument' होना संभव है या नहीं। – Alderath

+0

@ सैंटोश - मुझे यकीन नहीं है कि यह ओ (एन + एम) समस्या है क्योंकि लूप को प्रत्येक एम बच्चों के माध्यम से बार-बार फिर से भरने की ज़रूरत होती है, जिससे यह ओ (एन * एम) या ओ (एन) की समय जटिलता देता है।^2)। –

उत्तर

3

आप एक हैंडलर में किसी दस्तावेज़ के साथ क्या करना चाहते हैं उसे समेकित कर सकते हैं। यह आपको भविष्य में नए हैंडलर को परिभाषित करने की अनुमति देगा कि आप मौजूदा कोड में जा सकते हैं।

interface DocumentHandler { 
    void process(Document d); 
} 

class ExportToPdf implements DocumentHandler { ... } 
class AppendToParentPdf implements DocumentHandler { ... } 

// Now you're just passing the interface whose implementation does something with the document 
void handleDocument(DocumentHandler parentHandler, DocumentHandler childHandler) { 
    for(Document parent : documents) { 
     parentHandler.process(parent); 

     for(Document child : parent.children()) { 
      childHandler.process(child); 
     } 
    } 
} 

DocumentHandler appendToParent = new AppendToParentPdf(); 
DocumentHandler exportToPdf = new ExportToPdf(); 

// pass the child/parent handlers as needed 
handleDocument(exportToPdf, appendToParent); 
handleDocument(exportToPdf, exportToPdf); 

दक्षता के रूप में, मैं कहूंगा कि जब तक आप प्रदर्शन समस्याओं में भाग नहीं लेते तब तक अनुकूलित करने का प्रयास न करें। किसी भी मामले में, समस्या नेस्टेड लूप के साथ नहीं होगी बल्कि तर्क के साथ ही दस्तावेज़ों को संसाधित करता है।

+0

धन्यवाद। यह एक सुंदर सुरुचिपूर्ण स्निपेट है। –

+0

धन्यवाद! मदद करने में खुशी हुई :) – armandino

1

मैं एक टिप्पणी में यह फिट करने की कोशिश की है, लेकिन वहाँ कहने के लिए बहुत ज्यादा है ...

मैं नहीं दिख रहा है कि कैसे परिवर्तन के बारे में आप बात कर रहे हैं एक कोड गंध है। यदि आवश्यकताएं इस सरल कार्य के लिए बदलती हैं, तो वे बदल जाते हैं। अगर आपको केवल एक ही स्थान में बदलाव करने की ज़रूरत है, तो ऐसा लगता है जैसे आपने अच्छा काम किया है। यदि आपके क्लाइंट को इसे करने के दोनों तरीकों की आवश्यकता होगी (या अधिक), तो आप किसी प्रकार के रणनीति पैटर्न पर विचार कर सकते हैं ताकि आपको कार्य करने के लिए आसपास के कोड को फिर से लिखना पड़े।

यदि आप प्रति सप्ताह इन परिवर्तनों में से दर्जनों बदलाव कर रहे हैं, तो यह गन्दा हो सकता है और आपको संभवत: एक बहुत ही व्यस्त धुरी के साथ प्रभावी तरीके से निपटने के लिए योजना बनाना चाहिए। अन्यथा, अनुशासन और रिफैक्टरिंग आपको इसे साफ रखने में मदद कर सकती है।

एन² एक समस्या है या नहीं, यह निर्भर करता है। एन कितना बड़ा है? यदि आपको इसे अक्सर करना है (यानि प्रति घंटा दर्जनों बार) और n उनमें से 1000 में है, तो आपको कोई समस्या हो सकती है। अन्यथा जब तक आप मांग या उससे अधिक हो रहे हैं, तब तक मैं इसे पसीना नहीं पड़ेगा और आपका सीपीयू/डिस्क उपयोग खतरे के क्षेत्र से बाहर है।

+0

उत्तर के लिए धन्यवाद। समस्या यह है कि संभावित रूप से 1 मिलियन + दस्तावेज (माता-पिता + बच्चे) 300+ उपयोगकर्ताओं द्वारा किसी दिए गए बिंदु पर निर्यात किए जा सकते हैं और हालांकि कोई भी उप-दूसरे निर्यातक जादू होने की उम्मीद नहीं कर रहा है, इस प्रणाली में होने की संभावना है इस तरह के प्रक्षेपित भार से कर लगाया। –

+0

यहां तक ​​कि यदि लाखों दस्तावेज हैं, तो उपयोगकर्ता किसी दिए गए अनुरोध में कितने पूछने जा रहा है? एक समय में सिस्टम पर कितने उपयोगकर्ता होंगे, और उनमें से कितने समय में दस्तावेज़ तैयार करेंगे? जब तक कि आपके पास कुछ असामान्य आवश्यकताएं न हों, मैं उम्मीद करता हूं कि उन संख्याओं को कुछ उचित होने के लिए काम करना होगा। फिर भी, यदि आप बड़े पैमाने पर काम करने के बारे में चिंतित हैं, तो हो सकता है कि आप नौकरी कतारों पर विचार करना चाहें जो समवर्ती काम की मात्रा को कम करने के लिए हो। मैं इसके बारे में चिंता नहीं करता, हालांकि कुछ भार परीक्षण ने मुझे साबित कर दिया कि मुझे उनकी आवश्यकता है। – Bill

1

दूसरा सवाल 'समस्या सिर्फ प्रणाली export(Document doc); के साथ एक inteface Exporter बनाने और फिर विभिन्न स्वरूपों में से प्रत्येक के लिए लागू है, उदा हल किया जा सकता class DocExporterImpl implements Exporter

पहला व्यक्ति आपकी आवश्यकताओं पर निर्भर करता है और कोई डिज़ाइन पैटर्न नहीं है क्योंकि इन समस्याओं को हल करता है। वहां आपकी मदद नहीं कर सकता

2

अपने दूसरे प्रश्न के लिए, आप provider pattern या इसका विस्तार कर सकते हैं।

प्रदाता पैटर्न: यह पैटर्न रणनीति पैटर्न में अपनी जड़ें है और यह आप एक अमूर्त में अपने डेटा और व्यवहार डिजाइन इतना है कि आप किसी भी समय कार्यान्वयन बाहर स्वैप कर सकते हैं

4

हैं की सुविधा देता है वहाँ उपरोक्त के रूप में अभिभावक-बाल संबंधों के बेहतर प्रतिनिधित्व जहां ओ (एन^2) फैशन में सभी दस्तावेजों और उनके बच्चों के माध्यम से मेरे रास्ते को मजबूर करने के बजाय।

यह O(N^2) नहीं है। यह O(N) है जहां N माता-पिता और बाल दस्तावेजों की कुल संख्या है। यह मानते हुए कि किसी भी बच्चे के पास एक से अधिक मूल दस्तावेज़ नहीं हैं, तो आप प्रदर्शन में काफी सुधार नहीं कर सकते हैं। इसके अलावा, ट्रैवर्सल की लागत शायद पीडीएफ उत्पन्न करने वाली कॉल की लागत की तुलना में मामूली है।

एकमात्र ऐसा मामला जहां आप अनुकूलन पर विचार करना चाहें, यह है कि यदि बाल दस्तावेज़ कई माता-पिता के बच्चे हो सकते हैं। उस स्थिति में, आप उन दस्तावेजों का ट्रैक रखना चाह सकते हैं जिन्हें आपने पहले ही पीडीएफ बनाया है ... और अगर आप उन्हें ट्रैवर्सल में दोबारा संशोधित करते हैं तो उन्हें छोड़ दें। "मैंने इस दस्तावेज़ को पहले देखा है" के लिए परीक्षण HashSet का उपयोग करके कार्यान्वित किया जा सकता है।

+0

उत्तर के लिए धन्यवाद। मुझे समझ में नहीं आता कि लूप के लिए दो घोंसले कैसे एन^2 के बजाय समय जटिलता ओ (एन + एम) या ओ (एन) बनाते हैं। बाहरी-लूप का निष्पादन तब तक रुक जाएगा जब तक कि आंतरिक लूप निष्पादित नहीं हो जाता है, जब तक कि जावा कुछ कट्टरपंथी लूप-अनोलिंग को n^2 में n में बदल देता है। –

1

ट्रैक रखने के लिए एक सेट का उपयोग करके कौन से तत्व पहले ही निर्यात किए जा चुके हैं, यह सबसे सुंदर समाधान नहीं हो सकता है, लेकिन यह दस्तावेज़ों को दो बार निर्यात करने से रोक देगा।

Set<Document> alreadyExported = new HashSet<Document>(); 

for(Document parentDocument:Documents){ 
    ExportToPdf(parentDocument); 
    for(Document childDocument:parentDocument.children()){ 
     if(!aldreadyExported.contains(childDocument)){ 
     ExportToPdf(childDocument); 
     alreadyExported.add(childDocument); 
     } 
    } 
} 
संबंधित मुद्दे