बड़े, कसकर युग्मित वर्गों को कैसे विभाजित करें?


14

मेरे पास कोड (और बढ़ते) की 2k से अधिक लाइनों के कुछ विशाल वर्ग हैं जो कि यदि संभव हो तो मैं रिफ्लेक्टर करना चाहूंगा, कुछ अधिक प्रकाश और स्वच्छ डिजाइन।

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

मैं एक बहुत ही ठोस उदाहरण दूंगा: मेरे पास एक वर्ग है Serverजो आने वाले संदेशों को संभालता है। ऐसा लगता है कि तरीकों है joinChatroom, searchUsers, sendPrivateMessage, आदि इन सभी पद्धतियों का हेरफेर नक्शे जैसे users, chatrooms, servers, ...

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

मुझे एक श्रेणी के चैटरूम बनाने की आवश्यकता होगी, लेकिन प्रत्येक अन्य वस्तुओं के संदर्भ में। एक वर्ग उपयोगकर्ता फिर से सभी अन्य वस्तुओं के संदर्भ के साथ, आदि।

मुझे लगता है कि मैं कुछ गलत कर रहा हूं।


यदि आप उपयोगकर्ता और टोकन जैसी कक्षाएं बनाते हैं, तो क्या इन कक्षाओं को केवल आम डेटा संरचना के संदर्भ की आवश्यकता होगी या वे एक दूसरे का संदर्भ लेंगे?

यहां कई संतोषजनक जवाब हैं, आपको एक चुनना चाहिए।
jeremyjjbrown 16

@jeremyjjbrown प्रश्न को स्थानांतरित कर दिया गया है और मैंने इसे खो दिया है। एक जवाब उठाया, thx।
मैथ्यू

जवाबों:


10

आपके विवरण से, मुझे लगता है कि आपके नक्शे विशुद्ध रूप से डेटा के बैग हैं, Serverविधियों में सभी तर्क के साथ । सभी चैटरूम लॉजिक को एक अलग वर्ग में धकेल कर, आप अभी भी डेटा वाले नक्शे से चिपके हुए हैं।

इसके बजाय, व्यक्तिगत चैट रूम, उपयोगकर्ताओं आदि को ऑब्जेक्ट के रूप में मॉडल करने का प्रयास करें। इस तरह, आप डेटा के विशाल मानचित्रों के बजाय, केवल एक निश्चित विधि के लिए आवश्यक विशिष्ट वस्तुओं के आसपास से गुजर रहे होंगे।

उदाहरण के लिए:

public class User {
  private String name;
  ...

  public void sendMessage(String message) {
    ...
  }
}

public class Chatroom {
  // users in this chatroom
  private Collection<User> users;

  public void add(User user) {
    users.add(user);
  }

  public void sendMessage(String msg) {
    for (User user : users)
      user.sendMessage(msg);
  }
}

public class Server {
  // all users on the server
  private Collection<User> users;

  // all chatrooms on the server
  private Collection<Chatroom> chatrooms;

  /* methods to handle incoming messages */
}

अब संदेशों को संभालने के लिए कुछ विशिष्ट तरीकों को कॉल करना आसान है:

चैट रूम में शामिल होना चाहते हैं?

chatroom.add(user);

एक निजी संदेश भेजना चाहते हैं?

user.sendMessage(msg);

एक सार्वजनिक संदेश भेजना चाहते हैं?

chatroom.sendMessage(msg);

5

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


4

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

आप तब तक इस प्रक्रिया को दोहरा सकते हैं जब तक कि आप वर्ग के डिजाइन से खुश न हों।

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


1
मार्टिन फाउलर की पुस्तक martinfowler.com/books/refactoring.html
Arul

1

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

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


1

कैसाब्लांका के आनंददायक उत्तर में जोड़ने के लिए - यदि कई वर्गों को कुछ प्रकार की इकाई (एक संग्रह में उपयोगकर्ताओं को जोड़ना, संदेशों को संभालना आदि) के साथ एक ही मूल चीजों को करने की आवश्यकता होती है, तो उन प्रक्रियाओं को भी अलग रखा जाना चाहिए।

ऐसा करने के कई तरीके हैं - वंशानुक्रम या रचना के द्वारा। विरासत के लिए, आप ठोस तरीकों कि उदाहरण के लिए संभाल उपयोगकर्ताओं या संदेशों को खेतों और कार्यक्षमता प्रदान के साथ सार आधार वर्ग का उपयोग कर सकते हैं, और संस्थाओं है की तरह chatroomऔर user(या किसी अन्य) उन वर्गों का विस्तार।

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

दोनों ही मामलों में, इंटरफेस की ओर कोड करना सुनिश्चित करें, लचीलेपन के लिए ठोस कक्षाएं नहीं।

कहा जा रहा है कि इस तरह के पैटर्न का उपयोग करते समय हमेशा जोड़ा जटिलता की लागत पर विचार करें - यदि आपको इसकी आवश्यकता नहीं है, तो इसे कोड न करें। यदि आप जानते हैं कि आप बहुत संभवत: यह नहीं बदलने जा रहे हैं कि उपयोगकर्ताओं / संदेशों को कैसे संभालना है, तो आपको रणनीति पैटर्न की संरचनात्मक जटिलता की आवश्यकता नहीं है - लेकिन चिंताओं को अलग करने और पुनरावृत्ति से बचने के लिए, आपको अभी भी सामान्य कार्यक्षमता को तलाक देना चाहिए ठोस उदाहरणों से जो इसका उपयोग करते हैं - और, यदि इसके विपरीत कोई मौजूद कारण नहीं हैं, तो ऐसी हैंडलिंग-कार्यक्षमता (चैटरूम, उपयोगकर्ता) के उपयोगकर्ताओं को एक ऑब्जेक्ट के साथ लिखें जो हैंडलिंग करता है।

इसलिए योग करने के लिए:

  1. जैसा कि कैसाब्लांका ने लिखा है: चैटरूम, उपयोगकर्ताओं आदि को अलग करना और इनकैप्सुलेट करना
  2. अलग-अलग सामान्य कार्यक्षमता
  3. डेटा या समुच्चय के अलग-अलग उदाहरणों पर अधिक जटिल कार्यक्षमता से तलाक-प्रतिनिधित्व (साथ ही पहुंच और उत्परिवर्तन) के लिए अलग-अलग कार्यक्षमता को अलग करने पर विचार करें (उदाहरण के लिए, searchUsersसंग्रह-कक्षा, या रिपॉजिटरी / पहचान-मानचित्र में कुछ ऐसा हो सकता है) )

0

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

आप कहते हैं कि आपका सर्वर वर्ग और आपका भविष्य का वर्ग वर्ग उपयोगकर्ताओं के बारे में डेटा साझा करता है, लेकिन यह डेटा अलग होना चाहिए। सर्वर में संभवतः उपयोगकर्ताओं का एक सेट होता है, जबकि एक टोकन, जो स्वयं एक सर्वर से संबंधित होता है, के उपयोगकर्ताओं का एक अलग समूह होता है, पहले सेट का एक उप-सेट, केवल वर्तमान में एक विशिष्ट उपयोगकर्ता में प्रवेश करने वाले उपयोगकर्ताओं के लिए।

यह एक ही जानकारी नहीं है, भले ही डेटा प्रकार समान हों।
एक अच्छे डिज़ाइन के कई फायदे हैं।

मैंने अभी तक फाउलर की उक्त पुस्तक नहीं पढ़ी है, लेकिन मैंने फॉलोवर द्वारा अन्य सामग्री को पढ़ा है और यह उन लोगों द्वारा सुझाया गया है जिन पर मुझे भरोसा है, इसलिए मैं दूसरों के साथ मिलकर काफी सहज महसूस करता हूं।


0

मानचित्रों को एक्सेस करने की आवश्यकता मेगा-क्लास को सही नहीं ठहराती है। आपको कई वर्गों में तर्क को अलग करना होगा, और प्रत्येक वर्ग के पास एक गेटअप विधि होनी चाहिए ताकि अन्य वर्ग नक्शे तक पहुंच सकें।


0

मैं उसी उत्तर का उपयोग करता हूं जो मैंने कहीं और प्रदान किया है: अखंड कक्षा लें और अन्य वर्गों के बीच अपनी जिम्मेदारियों को विभाजित करें। DCI और विज़िटर पैटर्न दोनों ऐसा करने के लिए अच्छे विकल्प प्रदान करते हैं।


-1

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.