क्या "सादे पुराने डेटा" कक्षाओं का उपयोग करने का कोई कारण है?


43

विरासत कोड में मुझे कभी-कभी ऐसी कक्षाएं दिखाई देती हैं जो डेटा के लिए रैपर के अलावा और कुछ नहीं हैं। कुछ इस तरह:

class Bottle {
   int height;
   int diameter;
   Cap capType;

   getters/setters, maybe a constructor
}

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

क्या कोई ऐसा मामला है जहां ऐसी वस्तुएं आवश्यक होंगी? यदि यह अक्सर उपयोग किया जाता है, तो क्या यह डिजाइन को संदिग्ध बनाता है?


1
यह काफी अपने प्रश्न का उत्तर नहीं है लेकिन फिर भी प्रासंगिक लगता है: stackoverflow.com/questions/36701/struct-like-objects-in-java
एडम लेअर

2
मुझे लगता है कि आप जिस पद की तलाश कर रहे हैं वह POD (Plain Old Data) है।
गौरव

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

1
यह ढेर अतिप्रवाह पर नहीं होना चाहिए?
मुअदीद

7
@ Muad'Dib: तकनीकी तौर पर, यह है प्रोग्रामर के बारे में। यदि आप सादे पुराने डेटा संरचनाओं का उपयोग करते हैं तो आपका कंपाइलर परवाह नहीं करता है। आपका सीपीयू शायद इसे पसंद करता है ("मैं कैश से ताज़ा डेटा की गंध पसंद करता हूं" तरह से)। यह उन लोगों के लिए है जो "अपनी कार्यप्रणाली को कम शुद्ध करते हैं?" प्रशन।
Shog9

जवाबों:


67

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

public void DoStuffWithBottle(Bottle b)
{
    // do something that doesn't modify Bottle, so the method doesn't belong
    // on that class
}

से

public void DoStuffWithBottle(int bottleHeight, int bottleDiameter, Cap capType)
{
}

एक वर्ग का उपयोग करना भी आपको DoStuffWithBottle के हर कॉलर को संशोधित किए बिना बोतल में एक अतिरिक्त पैरामीटर जोड़ने की अनुमति देता है। और आप बोतल को उप-वर्ग कर सकते हैं और जरूरत पड़ने पर अपने कोड की पठनीयता और संगठन को और बढ़ा सकते हैं।

उदाहरण के लिए, डेटाबेस डेटा क्वेरी के परिणामस्वरूप सादे डेटा ऑब्जेक्ट भी लौटाए जा सकते हैं। मेरा मानना ​​है कि इस मामले में उनके लिए शब्द "डेटा ट्रांसफर ऑब्जेक्ट" है।

कुछ भाषाओं में अन्य विचार भी हैं। उदाहरण के लिए, C # क्लासेस और स्ट्रक्चर्स में अलग-अलग व्यवहार होता है, क्योंकि स्ट्रक्चर्स एक वैल्यू टाइप होते हैं और क्लास रेफरेंस टाइप होते हैं।


25
नाह। DoStuffWithएक विधि होना चाहिए कीBottle OOP में वर्ग (और सबसे शायद अपरिवर्तनीय भी होना चाहिए)। आपने जो ऊपर लिखा है, वह एक ओओ भाषा में एक अच्छा पैटर्न नहीं है (जब तक कि आप एक विरासत एपीआई के साथ हस्तक्षेप नहीं कर रहे हैं)। यह है , तथापि एक गैर OO वातावरण में एक वैध डिजाइन,।
कोनराड रुडोल्फ

11
@ जेवियर: तब जावा सबसे अच्छा जवाब नहीं है। ओओ पर जावा का जोर भारी है, भाषा मूल रूप से किसी और चीज में अच्छी नहीं है।
कोनराड रूडोल्फ

11
@ जॉन: मैं बिल्कुल सरल था। लेकिन सामान्य तौर पर, OO Encapsulate में वस्तुओं राज्य , नहीं डेटा। यह एक अच्छा लेकिन महत्वपूर्ण अंतर है। OOP की बात ठीक है कि बहुत सारा डेटा आसपास नहीं बैठा है। यह उन राज्यों के बीच संदेश भेज रहा है जो एक नया राज्य बनाते हैं। मैं यह देखने में विफल रहता हूं कि आप या तो मेथड से या मेसेज कैसे भेज सकते हैं। (और यह ओओपी की मूल परिभाषा है इसलिए मैं इसे त्रुटिपूर्ण नहीं मानूंगा।)
कोनराड रूडोल्फ

13
@ कोनराड रूडोल्फ: यही कारण है कि मैंने स्पष्ट रूप से विधि के अंदर टिप्पणी की। मैं इस बात से सहमत हूं कि बॉटल की घटनाओं को प्रभावित करने वाले तरीके उस क्लास में जाने चाहिए। लेकिन अगर किसी अन्य वस्तु को बोतल में दी गई जानकारी के आधार पर अपने राज्य को संशोधित करने की आवश्यकता है, तो मुझे लगता है कि मेरा डिजाइन काफी मान्य होगा।
एडम लेअर

10
@ कोनराड, मैं असहमत हूं कि doStuffWithBottle को बोतल क्लास में जाना चाहिए। एक बोतल को यह क्यों पता होना चाहिए कि खुद के साथ सामान कैसे करना है? doStuffWithBottle इंगित करता है कि एक बोतल के साथ कुछ और कुछ करेगा। अगर बोतल में यह था, कि तंग युग्मन होगा। हालाँकि, यदि बोतल वर्ग में एक आइसफुल () विधि है, तो यह पूरी तरह से उचित होगा।
नेमी

25

कुछ मामलों में डेटा कक्षाएं मान्य हैं। डीटीओ एक अच्छा उदाहरण हैं, जिसका उल्लेख अन्ना लीयर ने किया है। सामान्य तौर पर, आपको उन्हें एक वर्ग के बीज के रूप में मानना ​​चाहिए, जिनके तरीके अभी तक अंकुरित नहीं हुए हैं। और यदि आप उनमें से बहुत से पुराने कोड में चल रहे हैं, तो उन्हें एक मजबूत कोड गंध मानें। वे अक्सर पुराने C / C ++ प्रोग्रामर द्वारा उपयोग किए जाते हैं जिन्होंने कभी OO प्रोग्रामिंग में बदलाव नहीं किया है और प्रक्रियात्मक प्रोग्रामिंग का संकेत है। गेटर्स पर भरोसा करना और हर समय (या इससे भी बदतर अभी तक, गैर-निजी सदस्यों की प्रत्यक्ष पहुंच पर) आपको यह जानने से पहले परेशानी में डाल सकता है। एक बाहरी विधि के उदाहरण पर विचार करें जिससे जानकारी की आवश्यकता हो Bottle

यहाँ Bottleएक डेटा वर्ग है):

void selectShippingContainer(Bottle bottle) {
    if (bottle.getDiameter() > MAX_DIMENSION || bottle.getHeight() > MAX_DIMENSION ||
            bottle.getCapType() == Cap.FANCY_CAP ) {
        shippingContainer = WOODEN_CRATE;
    } else {
        shippingContainer = CARDBOARD_BOX;
    }
}

यहाँ हमने Bottleकुछ व्यवहार दिया है):

void selectShippingContainer(Bottle bottle) {
    if (bottle.isBiggerThan(MAX_DIMENSION) || bottle.isFragile()) {
        shippingContainer = WOODEN_CRATE;
    } else {
        shippingContainer = CARDBOARD_BOX;
    }
}

पहला तरीका टेल-डोन-आस्क सिद्धांत का उल्लंघन करता है, और Bottleगूंगा रखकर हमने बोतलों के बारे में अंतर्निहित ज्ञान दिया है, जैसे कि एक नाजुक ( Cap) को क्या बनाता है , तर्क में पर्ची करें जो Bottleकक्षा के बाहर है । जब आप आदतों पर निर्भर हो जाते हैं तो इस तरह के 'रिसाव' को रोकने के लिए आपको अपने पैर की उंगलियों पर रहना पड़ता है।

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

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


1
विश्वास नहीं कर सकते कि इस उत्तर में कोई वोट नहीं है (ठीक है, आपके पास अभी एक है)। यह एक सरल उदाहरण हो सकता है, लेकिन जब OO के साथ दुर्व्यवहार किया जाता है, तो आपको सेवा कक्षाएं मिलती हैं जो बुरे सपने वाली कार्यक्षमता में बदल जाती हैं जिन्हें कक्षाओं में इनकैप्सुलेट किया जाना चाहिए था।
Alb

"पुराने C / C ++ प्रोग्रामर द्वारा जिन्होंने OO को कभी भी ट्रांज़िशन (एसआईसी) नहीं बनाया है"? C ++ प्रोग्रामर आमतौर पर बहुत ही अच्छे होते हैं, क्योंकि यह एक OO भाषा है, अर्थात C के बजाय C ++ का उपयोग करने का पूरा बिंदु
nappyfalcon

7

यदि यह आपकी जरूरत का सामान है, तो यह ठीक है, लेकिन कृपया, कृपया इसे पसंद करें

public class Bottle {
    public int height;
    public int diameter;
    public Cap capType;

    public Bottle(int height, int diameter, Cap capType) {
        this.height = height;
        this.diameter = diameter;
        this.capType = capType;
    }
}

बजाय कुछ की तरह

public class Bottle {
    private int height;
    private int diameter;
    private Cap capType;

    public Bottle(int height, int diameter, Cap capType) {
        this.height = height;
        this.diameter = diameter;
        this.capType = capType;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getDiameter() {
        return diameter;
    }

    public void setDiameter(int diameter) {
        this.diameter = diameter;
    }

    public Cap getCapType() {
        return capType;
    }

    public void setCapType(Cap capType) {
        this.capType = capType;
    }
}

कृप्या।


14
इसके साथ एकमात्र समस्या यह है कि कोई मान्यता नहीं है। किसी भी तर्क के रूप में कि एक मान्य बोतल बोतल वर्ग में क्या होनी चाहिए। हालांकि, आपके प्रस्तावित कार्यान्वयन का उपयोग करते हुए, मैं एक नकारात्मक ऊंचाई और व्यास के साथ एक बोतल रख सकता हूं - हर बार ऑब्जेक्ट का उपयोग किए बिना ऑब्जेक्ट पर किसी भी व्यावसायिक नियमों को लागू करने का कोई तरीका नहीं है। दूसरी विधि का उपयोग करके, मैं यह सुनिश्चित कर सकता हूं कि अगर मेरे पास एक बोतल वस्तु है, तो यह मेरे अनुबंध के अनुसार हमेशा एक मान्य बोतल वस्तु होगी।
थॉमस ओवेन्स

6
यह एक ऐसा क्षेत्र है जहाँ .NET में संपत्तियों पर थोड़ी बढ़त है, क्योंकि आप सत्यापन लॉजिक के साथ एक प्रॉपर्टी एक्सेसर जोड़ सकते हैं, उसी सिंटैक्स के साथ जैसे कि आप किसी फ़ील्ड को एक्सेस कर रहे थे। आप एक संपत्ति को भी परिभाषित कर सकते हैं जहां कक्षाएं संपत्ति का मूल्य प्राप्त कर सकती हैं, लेकिन इसे सेट नहीं करें।
जॉनएल

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

2
कंस्ट्रक्टर का उपयोग करने का लाभ यह है कि इससे कक्षा को अपरिवर्तनीय बनाना आसान हो जाता है। यदि आप मल्टी-थ्रेडेड कोड लिखना चाहते हैं तो यह आवश्यक है।
फार्च्युनर

7
मैं जब भी संभव हो खेतों को अंतिम रूप दूंगा। IMHO मैं डिफ़ॉल्ट रूप से अंतिम होने के लिए फ़ील्ड्स को प्राथमिकता देता और परस्पर फ़ील्ड के लिए एक कीवर्ड होता। जैसे var
पीटर लॉरी

6

जैसा कि @ अन्ना ने कहा, निश्चित रूप से बुराई नहीं है। सुनिश्चित करें कि आप संचालन (विधियाँ) कक्षाओं में रख सकते हैं, लेकिन केवल यदि आप करना चाहते हैं। आपको नहीं करना है।

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

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

  2. समस्या 1 को अधिसूचना विधियों में डालकर हल करें , ताकि यदि भाग ए को संशोधित किया जाए, तो यह भागों बी और सी के लिए आवश्यक परिवर्तनों को फैलाने की कोशिश करता है। प्राथमिक कारण है कि इसे एक्सेस-और-सेट एक्सेसर विधियों के लिए अनुशंसित किया जाता है। चूंकि यह अनुशंसित अभ्यास है, इसलिए यह समस्या 1 को बहाने के लिए प्रकट होता है, जिससे समस्या 1 और समाधान 2 से अधिक हो जाती है। इसका परिणाम न केवल बग में सूचनाओं को अपूर्ण रूप से लागू करने, बल्कि भगोड़ा सूचनाओं के प्रदर्शन-प्रदर्शन समस्या के कारण है। ये अनंत अभिकलन नहीं हैं, केवल बहुत लंबे हैं।

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

यहाँ मैं क्या करने की कोशिश कर रहा हूँ:

  1. डेटा को यथासंभव सामान्य रखें, ताकि जब डेटा में कोई परिवर्तन किया जाता है, तो यह असंगत स्थिति में प्रवेश करने की संभावना को कम करने के लिए, संभव के रूप में कुछ कोड बिंदुओं पर किया जाता है।

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


3

जब आप कुछ कारणों से मध्यम आकार / बड़े अनुप्रयोगों के साथ काम कर रहे हैं तो इस तरह की कक्षाएं काफी उपयोगी हैं:

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

तो संक्षेप में, मेरे अनुभव में वे आमतौर पर कष्टप्रद से अधिक उपयोगी होते हैं।


3

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


3

अन्ना लीयर से सहमत,

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

कभी-कभी लोग 1999 जावा कोडिंग कन्वेंशनों को पढ़ना भूल जाते हैं जिससे यह बहुत स्पष्ट हो जाता है कि इस तरह की प्रोग्रामिंग पूरी तरह से ठीक है। वास्तव में अगर आप इससे बचते हैं, तो आपके कोड से बदबू आएगी! (बहुत सारे गेटर्स / सेटर्स)

जावा कोड कन्वेंशन 1999 से: उपयुक्त सार्वजनिक उदाहरण चर का एक उदाहरण वह मामला है जहां वर्ग अनिवार्य रूप से एक डेटा संरचना है, जिसमें कोई व्यवहार नहीं है। दूसरे शब्दों में, यदि आपने एक वर्ग के बजाय एक संरचना का उपयोग किया होता (यदि जावा समर्थित संरचना), तो यह वर्ग के उदाहरण चर को सार्वजनिक करने के लिए उपयुक्त है। http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

जब सही तरीके से उपयोग किया जाता है, तो पीओजेओ (सादे पुराने डेटा संरचनाएं) पीओजेओ से बेहतर होते हैं, जैसे कि पीओजेओ अक्सर ईजेबी से बेहतर होते हैं।
http://en.wikipedia.org/wiki/Plain_Old_Data_Structures


3

जावा में भी संरचनाओं का अपना स्थान है। आपको केवल उनका उपयोग करना चाहिए यदि निम्नलिखित दो चीजें सत्य हैं:

  • आपको बस डेटा को एग्रीगेट करना होगा, जिसमें कोई व्यवहार नहीं है, उदाहरण के लिए एक पैरामीटर के रूप में
  • यह एक बिट से कोई फर्क नहीं पड़ता कि डेटा किस प्रकार के मूल्यों का है

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

हालाँकि, यदि उनमें से एक भी लागू नहीं होता है, तो आप एक वास्तविक वर्ग के साथ काम कर रहे हैं। अर्थात सभी क्षेत्र निजी होने चाहिए। (यदि आपको अधिक सुलभ दायरे में किसी क्षेत्र की आवश्यकता है, तो गेट्टर / सेटर का उपयोग करें।)

यह जांचने के लिए कि क्या आपके माना-संरचना में व्यवहार है, जब खेतों का उपयोग किया जाता है तो देखें। यदि यह बताने का उल्लंघन लगता है , तो मत पूछिए , फिर आपको उस व्यवहार को अपनी कक्षा में ले जाने की आवश्यकता है।

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

आपका बोतल उदाहरण सबसे अधिक संभावना दोनों परीक्षणों में विफल होगा। आपके पास (इस तरह दिखता है) कोड हो सकता है:

public double calculateVolumeAsCylinder(Bottle bottle) {
    return bottle.height * (bottle.diameter / 2.0) * Math.PI);
}

इसके बजाय यह होना चाहिए

double volume = bottle.calculateVolumeAsCylinder();

यदि आपने ऊंचाई और व्यास को बदल दिया, तो क्या यह एक ही बोतल होगी? शायद ऩही। वे अंतिम होना चाहिए। क्या व्यास के लिए ऋणात्मक मान ठीक है? आपकी बोतल चौड़ी होने की तुलना में लंबी होनी चाहिए? क्या कैप शून्य हो सकती है? नहीं? आप इसे कैसे मान्य कर रहे हैं? मान लें कि ग्राहक या तो मूर्ख या दुष्ट है। ( अंतर बताना असंभव है। ) आपको इन मूल्यों की जांच करने की आवश्यकता है।

यह आपके नए बोतल वर्ग की तरह लग सकता है:

public class Bottle {

    private final int height, diameter;

    private Cap capType;

    public Bottle(final int height, final int diameter, final Cap capType) {
        if (diameter < 1) throw new IllegalArgumentException("diameter must be positive");
        if (height < diameter) throw new IllegalArgumentException("bottle must be taller than its diameter");

        setCapType(capType);
        this.height = height;
        this.diameter = diameter;
    }

    public double getVolumeAsCylinder() {
        return height * (diameter / 2.0) * Math.PI;
    }

    public void setCapType(final Cap capType) {
        if (capType == null) throw new NullPointerException("capType cannot be null");
        this.capType = capType;
    }

    // potentially more methods...

}

0

IMHO अक्सर भारी ऑब्जेक्ट-ओरिएंटेड सिस्टम में इस तरह पर्याप्त कक्षाएं नहीं होती हैं । मुझे ध्यान से अर्हता प्राप्त करने की आवश्यकता है।

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

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

एक अधिक जटिल उदाहरण इकाई-घटक सिस्टम होगा जैसा कि अक्सर खेल इंजनों में उपयोग किया जाता है। उन मामलों में, घटक अक्सर कच्चे डेटा और कक्षाएं जैसे आपके द्वारा दिखाए गए हैं। हालांकि, उनका दायरा / दृश्यता सीमित हो जाती है क्योंकि आमतौर पर केवल एक या दो सिस्टम होते हैं जो उस विशेष प्रकार के घटक तक पहुंच सकते हैं। नतीजतन आप अभी भी उन प्रणालियों में आक्रमणकारियों को बनाए रखने के लिए काफी आसान पाते हैं और इसके अलावा, ऐसी प्रणालियों में बहुत कम object->objectबातचीत होती है, जिससे यह समझना आसान हो जाता है कि पक्षी की आंख के स्तर पर क्या हो रहा है।

ऐसे मामलों में आप कुछ इस तरह से समाप्त कर सकते हैं, जहां तक ​​बातचीत जाती है (यह आरेख बातचीत को इंगित करता है, न कि युग्मन, क्योंकि एक युग्मन आरेख में नीचे की दूसरी छवि के लिए सार इंटरफेस शामिल हो सकते हैं):

यहाँ छवि विवरण दर्ज करें

... इसके विपरीत:

यहाँ छवि विवरण दर्ज करें

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


-1

OOP की दुनिया में और भी अजीब जीव मौजूद हैं। मैंने एक बार एक वर्ग बनाया है, जो अमूर्त है, और इसमें कुछ भी नहीं है, यह सिर्फ अन्य दो वर्गों के एक आम अभिभावक के लिए है ... यह पोर्ट्स है:

SceneMember 
Message extends SceneMember
Port extends SceneMember
InputPort extends Port
OutputPort extends Port

इसलिए सीनमेम्बर बेस क्लास है, यह सभी काम करता है, जो कि दृश्य पर दिखाई देना आवश्यक है: ऐड, डिलीट, गेट-सेट आईडी आदि। संदेश बंदरगाहों के बीच संबंध है, इसका अपना जीवन है। InputPort और OutputPort में स्वयं के i / o विशिष्ट कार्य होते हैं।

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

शायद यह एक एंटीपैटर्न है , लेकिन मुझे यह पसंद है।

(यह "मेट" शब्द की तरह है, जिसका उपयोग "पत्नी" और "पति" दोनों के लिए किया जाता है। आप किसी ठोस व्यक्ति के लिए "मेट" शब्द का उपयोग कभी नहीं करते हैं, क्योंकि आप उसे / उसके लिंग को जानते हैं, और इससे कोई फर्क नहीं पड़ता। यदि वह शादीशुदा है या नहीं, तो आप इसके बजाय "किसी" का उपयोग करते हैं, लेकिन यह अभी भी मौजूद है, और इसका उपयोग दुर्लभ, अमूर्त स्थितियों में किया जाता है, जैसे कानून का पाठ।)


1
आपके पोर्ट को SceneMember को विस्तारित करने की आवश्यकता क्यों है? SceneMembers पर संचालित करने के लिए पोर्ट क्लासेस क्यों नहीं बनाई गई?
माइकल के

1
तो क्यों नहीं मानक मार्कर इंटरफ़ेस पैटर्न का उपयोग करें? मूल रूप से आपके खाली सार आधार वर्ग के समान है, लेकिन यह बहुत अधिक सामान्य मुहावरा है।
टीएमएन

1
@ मिचेल: केवल सैद्धांतिक कारणों से, मैंने पोर्ट को भविष्य में उपयोग के लिए आरक्षित किया था, लेकिन यह भविष्य में अभी तक नहीं आया है, और शायद कभी नहीं होगा। मुझे महसूस नहीं हुआ कि उनके नाम के विपरीत उनके पास कोई आम नहीं है। मैं उस खाली वर्ग के किसी भी नुकसान का सामना करने वाले सभी लोगों के लिए मुआवजा
दूंगा

1
@TMN: SceneMember (व्युत्पन्न) प्रकार में getMemberType () विधि है, ऐसे कई मामले हैं जब SceneMember ऑब्जेक्ट्स के सबसेट के लिए स्कैन किया जाता है।
ern0

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