2009-07-01 14 views
5
में संग्रह कक्षाएं encapsulating

मान लीजिए मैं निम्न प्रकार के डेटा है:विरासत और जावा

class Customer { 
    String id; // unique 
    OtherCustData someOtherData; 
} 

class Service { 
    String url; // unique 
    OtherServiceData someOtherData; 
} 

class LastConnection { 
    Date date; 
    OtherConnData someOtherData; // like request or response 
} 

अब मैं जब याद करने के लिए सेवाओं की प्रत्येक से जुड़े ग्राहकों के प्रत्येक की जरूरत है।
मैं संरचना बनाना होगा:

Map<Customer, Map<Service, LastConnection>> lastConnections; 

या, आईडी के आधार पर खोज करने में सक्षम हो और सभी बराबर लिखने के लिए है() और hashCode():

Map<String, Map<String, LastConnection>> lastConnections; 

अब मैं यहां पहुंच सकता है द्वारा

LastConnection connection = lastConnections.get(custId).get(srvUrl); 

यह सब बदसूरत लगता है, मैं LastConnections, एस के नक्शे के मानचित्र उम्मीद तरीकों के दसियों के लिए मानकों के रूप में यह पारित करने के लिए विशेष रूप से है कि LastConnection डेटा ओ मैं अपने ही कक्षाएं बनाने की सोच रहा हूँ कि कुछ ऐसा दिखाई देगा जो:

class CustomerConnections { 
    Map<String, LastConnection> customerConnections; 
    LastConnection get(String srvUrl) { 
     return customerConnections.get(srvUrl); 
    } 
    ... // all other needed operations; 
} 

class AllConnections { 
    Map<String, CustomerConnections> allConnections; 
    public LastConnection get(String custId, String srvUrl) { 
     return get(custId).get(srvUrl); 
    } 
    public CustomerConnection get(String custId) { 
     return allConnections.get(custId); 
    } 
    ... // all other needed operations; 
} 

समस्या यह है कि यह है:

class CustomerConnections extends HashMap<String, LastConnection> { 
} 

class AllConnections extends HashMap<String, CustomerConnections> { 
    public LastConnection get(String custId, String srvUrl) { 
     return get(custId).get(srvUrl); 
    } 
} 

ठीक है, मैं पहले से ही पता चला कि विरासत 3v1l है, इसलिए की रचना की कोशिश करते हैं मुझे यकीन नहीं है कि सॉलिड सिद्धांतों और सभी सर्वोत्तम प्रथाओं का सम्मान करने का सबसे अच्छा तरीका क्या होगा। कक्षाओं को बनाना जो पहले से मौजूद संग्रहों को विस्तारित करने के अलावा कुछ भी नहीं करते हैं, वे आवश्यकता से परे इकाइयों को गुणा करने की तरह लगते हैं, लेकिन मेरे कोड को और स्पष्ट कर देंगे (विशेष रूप से जब अगले स्तर होते हैं - जैसे महीने के सभी ऑकनेक्शन के मानचित्र और इसी तरह)। कोई निर्देश?

उत्तर

5

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

मैं संपुटित का विस्तार बदल जाएगा परे संस्थाओं गुणा की तरह लगता है। आप इस जानकारी को कैसे संग्रहीत करते हैं इसका विवरण छुपा रहे हैं। आपकी कक्षा के ग्राहकों को यह जानने की आवश्यकता नहीं है कि आप उन्हें ग्राहक कनेक्शन इतिहास के साथ कैसे प्रदान कर रहे हैं। मुझे लगता है कि यह एक अच्छा विचार है क्योंकि आप एपीआई के क्लाइंट को अपना कोड बदलने के बिना अंतर्निहित मॉडल बदल सकते हैं।

लेकिन मेरे कोड और अधिक स्पष्ट

यह बहुत अच्छा है और यह करने के लिए एक अच्छा कारण है होगा। YourClass.getCustomerConnection (cId) आपकेCollection.get (id) .get (id) .getConnection() से बहुत स्पष्ट है।इस कोड का उपयोग करके लोगों के जीवन को आसान बनाना होगा, भले ही आप उस व्यक्ति हों।

(खासकर जब वहाँ अगले स्तर हैं - AllConnections के मानचित्र की तरह महीने से और इतने पर)

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

-1

आप एक वर्ग बना सकते हैं कि लागू करताMap<K,V>, और आंतरिक रूप से एक कंटेनर नक्शा प्रतिनिधि:

class CustomerConnections implements Map<String,LastConnection> { 
    private Map<String, LastConnection> customerConnections; 

    @Override 
    public LastConnection get(Object srvUrl) { 
     return customerConnections.get(srvUrl); 
    } 
    // all other needed operations; 
} 

इस दृष्टिकोण के साथ अच्छी बात यह है कि आप एक Map जो एक मानक है चारों ओर पारित कर सकते हैं, अच्छी तरह से है - निर्धारित अनुबंध, लेकिन आप लाइब्रेरी कक्षाओं को विस्तारित करने से बचते हैं, जो अक्सर फहराया जाता है।

संपादित: जैसा कि नीचे कहे अनुसार, इस तरीके कि अंतर्निहित संग्रह

+2

इसके अलावा निर्दोष छोटे "अन्य सभी आवश्यक संचालन" टिप्पणी बॉयलरप्लेट प्रतिनिधिमंडल के मीट्रिक बटलोड को छुपाती है। –

+0

@ माइकल फेयर प्वाइंट – butterchicken

+1

हालांकि आपको केवल एक बार ऐसा करना है। एक प्रतिनिधिमंडल लागू करता है मानचित्र ऐसे सभी एक्सटेंशन के लिए बेस क्लास के रूप में उपयोग किया जा सकता है। – paulcm

0

custId+"#"+srvurl का उपयोग सरल Map<String, LastConnection> में एक कुंजी के रूप में क्यों नहीं करें?

या Tuple या जोड़ी कक्षा का उपयोग कुंजी के रूप में करें जिसमें दो आईडी शामिल हैं और hashCode() और equals() - "सबसे साफ" ओओ समाधान लागू करता है।

+0

किसी भी कुंजी के रूप में custId + "#" + srvUrl का उपयोग करने से मुझे सभी ग्राहक के कनेक्शन तुरंत प्राप्त करने की अनुमति नहीं मिल जाएगी। लेकिन वैसे भी ट्यूपल लाइब्रेरी के विचार के लिए धन्यवाद, मैं इसे देख लूंगा। – Jakub

+0

ठीक है, वह आपकी मूल समस्या descritpion का हिस्सा नहीं था; उस स्थिति में मानचित्र का मानचित्र शायद सबसे अच्छा विकल्प है। –

1

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

I इसे मानचित्र या अन्य प्रसिद्ध संग्रह वर्ग से प्राप्त नहीं करेगा, क्योंकि इस जानकारी को संग्रहीत करने के अर्थशास्त्र भविष्य में बदल सकते हैं।

इसके बजाय एक वर्ग है जो एक साथ एक ग्राहक और इसके संबंध बांध को लागू है, और उस वर्ग के अंदर उचित संग्रह क्लास का उपयोग

(इंटरफेस और अपने कोड के बाकी को प्रभावित किए बिना कि आप स्वतंत्र हैं बाद में बदलने के लिए)

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

0

आप उन वस्तुओं के बाहर वस्तुओं के बीच संबंधों को क्यों बनाए रखते हैं।

मैं निम्नलिखित की तरह कुछ सुझाव देंगे:

public class Customer 
{ 
    public List<LastConnection> getConnectionHistory() 
    { 
    ... 
    } 

    public List<LastConnection> getConnectionHistory(Service service) 
    { 
    ... 
    } 

    public List<LastConnection> getConnectionHistory(Date since) 
    { 
    ... 
    } 
} 

public class LastConnection 
{ 
    public Date getConnectionTime() 
    { 
    ... 
    } 

    public Service getService() 
    { 
    ... 
    } 
} 

फिर आप तरीकों कि इस जानकारी का उपयोग करने के लिए List<Customer> गुजरती हैं।

+0

लेकिन फिर मेरे ग्राहक वर्ग को अंतिम कनेक्शन कनेक्शन के बारे में पता होना चाहिए। मैं विभिन्न पैकेजों के बीच कई चक्रों के साथ समाप्त हो सकता है। विदाई, पुन: प्रयोज्यता ... मान लीजिए कि मेरे कोड में चार पैकेज हैं: कोर, लास्टकनेक्शन, एड्रेसबुक और ट्रांसएक्शन हिस्ट्री (केवल उदाहरण)। अगर मैंने mypackage.core.Customer को LastConnections, AddressBook और TransactionHistory के बारे में पता है (और प्रबंधित करें) यह गड़बड़ करेगा। मैं चाहता हूं कि LastConnection ग्राहक और एड्रेसबुक के बारे में जानता है ग्राहक के बारे में जानता है और इसी तरह से। अगली कार्यक्षमता को लागू करने का तरीका मौजूदा कोड को नहीं बदलेगा। – Jakub

+0

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

1

मुझे लगता है कि तुम भी विचार करना चाहिए कि कैसे संग्रह इस्तेमाल किया जा जा रहे हैं और कैसे डेटा प्राप्त किया जाता है:

  • अगर वे सरल परिणाम (उदाहरण के लिए) एक पृष्ठ पर प्रदर्शित किया है, तो सेट कर रहे हैं मानक संग्रह का उपयोग करना उचित लगता है - और फिर आप उन्हें कुशल बनाने के लिए कई मानक पुस्तकालयों का उपयोग कर सकते हैं।
  • दूसरी तरफ, यदि वे उत्परिवर्तनीय हैं और किसी भी बदलाव को जारी रखने की आवश्यकता है (उदाहरण के लिए), तो उन्हें अपने स्वयं के वर्गों में encapsulating बेहतर हो सकता है (जो डेटाबेस में परिवर्तन लिख सकते हैं, आदि)।

आप अपने डेटा को कैसे प्राप्त और बनाते हैं? यदि यह किसी डेटाबेस में संग्रहीत है, तो हो सकता है कि आप डेटास्ट्रक्चर को बनाए रखने के बजाय ग्राहक और/या सेवा और/या महीने द्वारा LastConnections का चयन करने के लिए SQL का उपयोग कर सकें (और केवल सरल सूचियों या कनेक्शन के मानचित्र या कनेक्शन की गणना)। या हो सकता है कि आप प्रत्येक अनुरोध के लिए कोई क्वेरी नहीं चलाना चाहते हैं, इसलिए पूरे डेटास्ट्रक्चर को स्मृति में रखने की आवश्यकता है।

Encapsulation आम तौर पर एक अच्छी बात यह है, विशेष रूप से, क्योंकि यह आपको Law of Demeter का पालन करने में मदद कर सकते हैं - हो सकता है आप कार्य है कि आप AllConnections वर्ग में वापस संग्रह पर प्रदर्शन करेंगे के कुछ (जो प्रभावी रूप से एक डीएओ है धक्का कर सकते हैं)। यह अक्सर इकाई परीक्षण में मदद कर सकता है।

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

class AllConnections extends HashMap<String, CustomerConnections> { 
    public LastConnection get(String custId, String srvUrl) { 
     return get(custId).get(srvUrl); 
    } 
} 
संबंधित मुद्दे