2009-02-23 15 views
10

मैंने अभी जावा सीखना शुरू कर दिया है और यह उत्सुक है कि जावा में अच्छी ऑब्जेक्ट अपघटन के लिए यह कोई अच्छा अभ्यास है? मुझे एक समस्या का वर्णन करने दें। बड़े सॉफ्टवेयर प्रोजेक्ट में यह हमेशा 'कोर' या 'यूई' जैसी बड़ी कक्षाएं होती है जिसमें बहुत सी विधियां होती हैं और छोटे वर्गों के बीच मध्यस्थ के रूप में लक्षित होती हैं। उदाहरण के लिए, यदि उपयोगकर्ता कुछ विंडो पर एक बटन क्लिक करता है, तो इस विंडो की कक्षा 'ui' कक्षा में एक संदेश भेजती है। यह 'ui' वर्ग इस संदेश को पकड़ता है और आवेदन प्रयोक्ता इंटरफ़ेस (इसके सदस्य की ऑब्जेक्ट्स में से किसी एक को कॉल करने के तरीके के माध्यम से) या एप्लिकेशन 'कोर' पर संदेश पोस्ट करके तदनुसार कार्य करता है यदि यह 'एक्जिट एप्लिकेशन' या 'स्टार्ट नेटवर्क' जैसा कुछ है कनेक्शन '।जावा में बिग क्लास अपघटन

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

जावा में ऐसी वस्तुओं को विभाजित करके कोई अभ्यास?

उत्तर

13

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

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

उदाहरण के लिए Wikipedia's Delegation pattern चर्चा देखें।

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

बुद्धि के लिए

, यदि आप एक बड़े वर्ग के लिए निम्न विधियों, प्रत्येक युक्त व्यापार तर्क, कई अन्य तरीकों के बीच युक्त साथ बाहर शुरू कर दिया:

... 
public boolean isManagement() { ... } 
public boolean isExecutive() { ... } 
public int getYearsOfService() { ... } 
public Date getHireDate() { ... } 
public int getDepartment() { ... } 
public BigDecimal getBasePay() { ... } 
public BigDecimal getStockShares() { ... } 
public boolean hasStockSharePlan() { ... } 
... 

तो इस बड़े वस्तु सकता है, इसके निर्माता में, एक नए बनाने

// Newly added variables, initialized in the constructor (or as appropriate) 
private final StaffType  staffType; 
private final PayInformation payInformation; 
private final PayInformation payInformation; 

... 

public boolean isManagement() { return staffType.isManagement(); } 
public boolean isExecutive() { return staffType.isExecutive(); } 
public int getYearsOfService() { return staffInformation.getYearsOfService(); } 
public Date getHireDate() { return staffInformation.getHireDate(); } 
public int getDepartment() { return staffInformation.getDepartment(); } 
public BigDecimal getBasePay() { return payInformation.getBasePay(); } 
public BigDecimal getStockShares() { return payInformation.getStockShares(); } 
public boolean hasStockSharePlan() { return payInformation.hasStockSharePlan(); } 
... 

जहां पूर्ण: निर्मित ऑब्जेक्ट StaffType और एक नव निर्मित वस्तु PayInformation और एक नव निर्मित वस्तु StaffInformation, और शुरू में बड़ा वस्तु में इन विधियों की तरह लग रहे हैं तर्क जो कि बड़ी वस्तु में होता था, इन तीन नई छोटी वस्तुओं में स्थानांतरित हो गया है। इस परिवर्तन के साथ, आप बड़े ऑब्जेक्ट का उपयोग करने वाले किसी भी चीज़ को छूए बिना छोटे ऑब्जेक्ट को छोटे हिस्सों में तोड़ सकते हैं। हालांकि, जैसा कि आप समय के साथ ऐसा करते हैं, आप पाएंगे कि बड़ी वस्तु के कुछ ग्राहकों को केवल विभाजित घटकों में से किसी एक तक पहुंच की आवश्यकता हो सकती है। इन ग्राहकों के लिए, बड़ी वस्तु का उपयोग करके और विशिष्ट वस्तु को प्रतिनिधि देने के बजाय, वे छोटी वस्तु का प्रत्यक्ष उपयोग कर सकते हैं। लेकिन अगर यह रिफैक्टरिंग कभी नहीं होती है, तो आपने अलग-अलग वर्गों में असंबद्ध वस्तुओं के व्यावसायिक तर्क को अलग करके चीजों में सुधार किया है।

+0

"मूल बड़ी कक्षा में, एक प्रतिनिधिमंडल विधि बनाएं जो" <- एक विधि "या प्रत्येक के लिए विधियों को आसानी से पास करे भगवान ऑब्जेक्ट के विघटित कार्यों का? – grigoryvp

+0

@ नरक का ईई: मैंने आपके प्रश्न का उत्तर देने के लिए अपना उत्तर बढ़ाया। – Eddie

+0

स्टाफ टाइप के अंदर कोड बहुत मुश्किल समय होगा भगवान ऑब्जेक्ट के तरीकों तक पहुंचना। आपको निर्भरता की आवश्यकता होगी कि भगवान ऑब्जेक्ट के संदर्भ को स्टाफ टाइप पर वापस डालें। जावा में ऐसी चीजों को करने का यह अनुशंसित तरीका है? – grigoryvp

1

मैंने कुछ मामलों को देखा है जहां यह विरासत द्वारा हल किया गया है: मान लें कि कक्षा बिग 5 अलग-अलग चीजों का ख्याल रखती है, और (विभिन्न कारणों से) उन्हें सभी को एक ही कक्षा में होना है। तो तुम एक मनमाना विरासत आदेश चुनें, और निर्धारित करें:

BigPart1 // all methods dealing with topiC#1 
BigPart2 extends BigPart1 // all methods dealing with topiC#2 
... 
Big extends BigPart4 // all methods dealing with the last topic. 

तुम सच में बातें, ऊपर परत कर सकते हैं ताकि टूटना समझ में आता है हो सकता है (Part2 वास्तव में सामान Part1 से उपयोग करता है, लेकिन ठीक इसके विपरीत, आदि) तो यह कुछ समझ में आता है।

वह स्थान जहां मैंने इसे देखा है, वेबवर्क्स में है, जहां एक वर्ग में गेटटर/सेटर विधियों के बहुत सारे होते हैं - निर्भरता इंजेक्शन के लिए उपयोग किए जाने वाले सेटर्स (उदाहरण के लिए, यूआरएल तर्क निष्पादन पर ऑब्जेक्ट को पास किया जाता है) और गेटर्स विभिन्न पेज टेम्पलेट्स के लिए मूल्यों को सुलभ बनाने के लिए (मुझे लगता है कि यह जेएसपी था)।

तो, टूटने वर्गीकृत किया सामान तार्किक, जैसे, यह मानते हुए वर्ग MyAction बुलाया गया था, वहाँ था MyActionBasicArgs (खेतों और बुनियादी सीजीआई तर्क के लिए setters), MyActionAdvancedArgs (उन्नत विकल्प args), MyActionExposedValues ​​के लिए बढ़ा दी द्वारा बढ़ाया (टिककर खेल) , MyActionDependencies (वसंत निर्भरता इंजेक्शन द्वारा उपयोग किए जाने वाले सेटर्स, गैर-सीजीआई तर्क) द्वारा विस्तारित, MyAction द्वारा विस्तारित (जिसमें वास्तविक निष्पादन() विधि शामिल है)।

वेबवर्क्स में निर्भरता इंजेक्शन के तरीके (या कम से कम, काम करने के लिए उपयोग किया जाता है) के कारण, यह एक विशाल वर्ग होना था, इसलिए इस तरह से इसे तोड़ने से चीजों को और अधिक बनाए रखा जा सकता था। लेकिन सबसे पहले, कृपया, कृपया देखें कि क्या आप केवल एक विशाल वर्ग से बच सकते हैं; अपने डिजाइन के बारे में सावधानी से सोचें।

+0

दुर्भाग्यवश यह अच्छा है अगर कार्यक्रम के हिस्सों को पदानुक्रमित रूप से व्यवस्थित किया गया हो। वास्तविक जीवन में, "xml parse", "नेटवर्क सर्वर", "नेटवर्क क्लाइंट", "उपयोगकर्ता इंटरफ़ेस", "लॉग सुविधा" आदि के लिए मूल दिखने वाली चीजें हैं, ऐसे मामलों में किसी अन्य प्रतिनिधिमंडल समूह को प्राप्त करना मुश्किल है :) – grigoryvp

+0

मुझे लगता है कि यह एक बहुत बुरा विचार है। एक विधि के लिए यह बहुत आसान है, कहें, BigPart4 को गलती से सुपरक्लास की विधि को ओवरराइड करने के लिए। दिलचस्प विचार लेकिन यह संभव है कि इस तरह जावा की विरासत का दुरुपयोग न करें। –

+0

@ नरक के ईई मुझे लगता है कि यहां विचार क्लासिक अर्थ में विरासत का उपयोग नहीं करना है, बल्कि इसके बजाय तार्किक समूहों में विधियों को विभाजित करना है ताकि .java फ़ाइलें पठनीय हो जाएं। क्लाइंट कोड में हमेशा बिग का संदर्भ होता है जिसमें अभी भी सभी विधियां होती हैं। –

1

अगला लॉजिकल चरण BigClass को जावा पैकेज में बदलने के लिए हो सकता है। इसके बाद संबंधित कार्यक्षमता के प्रत्येक समूह के लिए नई वस्तुएं बनाएं (प्रत्येक वर्ग में नोट करना कि ऑब्जेक्ट नए पैकेज का हिस्सा है)।

ऐसा करने के लाभ निर्भरता में कमी और प्रदर्शन हैं।

  1. पूरे पैकेज आयात करने के लिए कोई ज़रूरत नहीं/BigClass बस कुछ ही तरीकों मिलता है।
  2. संबंधित कार्यक्षमता में कोड परिवर्तन पूरे पैकेज/BigClass के पुन: संकलित/पुन: नियोजन की आवश्यकता नहीं है।
  3. कम स्मृति का उपयोग ऑब्जेक्ट आवंटित/हटाने के लिए किया गया है, क्योंकि आप छोटे वर्गों का उपयोग कर रहे हैं।
+0

और इस तरह के कई ऑब्जेक्ट्स-इन-पैकेज को कैसे संबोधित किया जाए? उदाहरण के लिए, मैं 'कोर' क्लास को 'कोर' पैकेज में तोड़ता हूं और अब इसमें core.ui.main, core.ui.log इत्यादि है और अब एक लॉग विंडो कोर को सूचित करना चाहता है कि उपयोगकर्ता 'सॉर्ट' बटन पर क्लिक करता है। यह core.ui.log.sort() को कैसे कॉल कर सकता है? सभी विधियों स्थिर होना चाहिए या? – grigoryvp

+0

आप करेंगे: आयात core.ui. *; फिर या तो तत्काल लॉग करें या सॉर्ट() विधि को स्थिर रूप से कॉल करें, हालांकि आपके पास कोड चीजें हैं। –

0

हां, सी # आंशिक कक्षाएं प्रदान करता है। मुझे लगता है यह है कि क्या आप जब आप कहते हैं की बात कर रहे है:

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

इस विशाल कक्षाओं अधिक प्रबंधनीय बनाने में मदद करता है। हालांकि, मुझे आंशिक कक्षाओं का सबसे अच्छा उपयोग होता है जब किसी को कोड जनरेटर द्वारा बनाए गए कोड को बढ़ाने की आवश्यकता होती है। जब एक वर्ग जितना बड़ा होता है उतना बड़ा होता है, तो इसे लगभग हमेशा ऑब्जेक्ट उन्मुख डिज़ाइन द्वारा छोटे वर्गों में विभाजित किया जा सकता है। आंशिक वर्ग का उपयोग करने से अधिक सही ऑब्जेक्ट उन्मुख डिज़ाइन होता है, जो कभी-कभी ठीक होता है क्योंकि अंतिम लक्ष्य स्थिर, भरोसेमंद, रखरखाव कोड है, और ओओ कोड का पाठ्यपुस्तक उदाहरण नहीं है।हालांकि, कई बार, एक बड़ी वस्तु के कोड को एक ही कक्षा के छोटे आंशिक वर्ग के उदाहरणों में डालने का आदर्श समाधान नहीं है।

यदि आप संभवतः "ईश्वर" वस्तु के गुणों का सबसेट ढूंढ सकते हैं जो एक दूसरे के साथ बातचीत नहीं करते हैं, तो उन सेटों में से प्रत्येक एक तार्किक रूप से एक नए ऑब्जेक्ट प्रकार के लिए एक अच्छा उम्मीदवार बना देगा। हालांकि, अगर इस "भगवान" वस्तु के सभी गुण एक दूसरे पर निर्भर करते हैं, तो वस्तु को विघटित करने के लिए आप इतना कुछ नहीं कर सकते हैं।

1

मुझे नहीं पता कि आपके पास इतनी बड़ी कक्षा क्यों होगी।

मुझे लगता है कि यदि आप एक गुई बिल्डर कोड पीढ़ी का उपयोग कर रहे थे और इसके बारे में आलसी हो रहे थे, तो आप ऐसी स्थिति में समाप्त हो सकते हैं, लेकिन जब तक आप स्वयं को नियंत्रित नहीं करते हैं तो कोडेजन आम तौर पर खराब हो जाता है।

मनमाने ढंग से एक वर्ग को विभाजित करना एक भयानक निर्मित समस्या का एक भयानक समाधान है। यदि आप एक GUI बिल्डर का उपयोग करना है, तो (कोड पुन: उपयोग, एक बात के लिए लगभग असंभव हो जाएगा)

, यह छोटे घटकों का निर्माण किया है, तो छोटे घटकों का उपयोग एक बड़ा जीयूआई का निर्माण करने के। प्रत्येक घटक को बिल्कुल एक काम करना चाहिए और इसे अच्छी तरह से करना चाहिए।

अगर आप इससे बच सकते हैं तो जेनरेट कोड संपादित करने की कोशिश न करें। एक व्यापार "तर्क" में व्यापार तर्क डालना सिर्फ एक भयानक डिजाइन पैटर्न है। अधिकांश कोड जनरेटर इस के साथ बहुत उपयोगी नहीं हैं, इसलिए बाहरी कक्षाओं से आपको जो चाहिए उसे प्राप्त करने के लिए केवल एक, न्यूनतम संपादन करने का प्रयास करें (एमवीसी सोचें जहां जेनेड कोड आपका दृश्य है और आपके द्वारा संपादित कोड आपके मॉडल में होना चाहिए और नियंत्रक)।

कभी-कभी आप फ़्रेम ऑब्जेक्ट से getComponents विधि का पर्दाफाश कर सकते हैं, कंटेनरों के माध्यम से पुनरावृत्त करके सभी घटकों को प्राप्त कर सकते हैं और फिर गतिशील रूप से उन्हें डेटा और कोड (अक्सर नाम संपत्ति के लिए बाध्यकारी) पर बाध्य कर सकते हैं, मेरे पास है इस तरह फॉर्म संपादकों का सुरक्षित रूप से उपयोग करने में सक्षम है, और सभी बाध्यकारी कोड बहुत आसानी से सारणित और पुन: उपयोग किया जाता है।

यदि आप जेनरेट कोड के बारे में बात नहीं कर रहे हैं - ठीक है तो अपने "भगवान" वर्ग में, क्या यह वास्तव में एक छोटी सी नौकरी करता है और यह अच्छा करता है? यदि नहीं, तो "नौकरी" खींचें, इसे अपनी कक्षा में रखें, और इसे प्रतिनिधि दें।

क्या आपका ईश्वर वर्ग पूरी तरह से फैक्टर है? जब मैंने इस तरह के विशाल वर्गों को देखा है, तो मैंने आमतौर पर बहुत सारी प्रतिलिपि/पेस्ट/संपादन लाइनों को देखा है। यदि कुछ खंड की प्रतिलिपि बनाने और अतीत करने और संपादित करने के लिए पर्याप्त समानता है, तो इन पंक्तियों को कोड के एक हिस्से में कारक करने के लिए पर्याप्त है।

यदि आपकी बड़ी कक्षा एक जीयूआई कक्षा है, तो सजावटकर्ताओं पर विचार करें - पुन: प्रयोज्य और आपकी मुख्य कक्षा से सामान निकालती है। एक डबल जीत

मुझे लगता है कि आपके प्रश्न का उत्तर यह है कि जावा में हम यह सुनिश्चित करने के लिए अच्छे ओओ का उपयोग करते हैं कि समस्या पहली जगह में नहीं उभरती है (या हम नहीं करते - जावा निश्चित रूप से उन समस्याओं से प्रतिरक्षा नहीं है जो आप हैं किसी अन्य भाषा की तुलना में किसी और के बारे में बात करना)

संबंधित मुद्दे