क्या विशिष्ट उदाहरणों के लिए उपवर्ग बनाना एक बुरा अभ्यास है?


37

निम्नलिखित डिजाइन पर विचार करें

public class Person
{
    public virtual string Name { get; }

    public Person (string name)
    {
        this.Name = name;
    }
}

public class Karl : Person
{
    public override string Name
    {
        get
        {
            return "Karl";
        }
    }
}

public class John : Person
{
    public override string Name
    {
        get
        {
            return "John";
        }
    }
}

क्या आपको लगता है कि यहां कुछ गड़बड़ है? मेरे लिए कार्ल और जॉन वर्गों को कक्षाओं के बजाय सिर्फ उदाहरण होना चाहिए क्योंकि वे बिल्कुल उसी तरह हैं:

Person karl = new Person("Karl");
Person john = new Person("John");

जब उदाहरण पर्याप्त हैं तो मैं नई कक्षाएं क्यों बनाऊंगा? कक्षाएं उदाहरण के लिए कुछ भी नहीं जोड़ती हैं।


17
दुर्भाग्य से, यह आपको बहुत सारे उत्पादन कोड में मिलेगा। जब आप इसे साफ कर सकते हैं।
एडम ज़करमैन

14
यह एक शानदार डिजाइन है - यदि कोई डेवलपर व्यवसाय डेटा में हर परिवर्तन के लिए खुद को अपरिहार्य बनाना चाहता है, और उसे 24/7 ;-) उपलब्ध होने में कोई समस्या नहीं है
डॉक ब्राउन

1
यहां एक प्रकार का संबंधित प्रश्न है जहां ओपी पारंपरिक ज्ञान के विपरीत मानता है। programmers.stackexchange.com/questions/253612/…
Dunk

11
व्यवहार नहीं डेटा के आधार पर अपनी कक्षाएं डिज़ाइन करें। मेरे लिए उप-वर्गों में पदानुक्रम में कोई नया व्यवहार नहीं जोड़ा गया है।
सोंगो

2
जावा में लैम्बदास के जावा 8 (जो कि अलग-अलग वाक्य रचना के साथ एक ही बात है) के आने से पहले जावा में अनाम उपवर्गों (जैसे घटना संचालकों) के साथ इसका व्यापक रूप से उपयोग किया जाता है।
marczellm

जवाबों:


77

प्रत्येक व्यक्ति के लिए विशिष्ट उपवर्ग होने की आवश्यकता नहीं है।

आप सही हैं, उन लोगों के बजाय उदाहरण होना चाहिए।

उपवर्गों का लक्ष्य: अभिभावक वर्गों का विस्तार करना

उपवर्गों का उपयोग मूल वर्ग द्वारा प्रदान की गई कार्यक्षमता को बढ़ाने के लिए किया जाता है । उदाहरण के लिए, आपके पास हो सकता है:

  • एक मूल वर्ग Batteryजो Power()कुछ कर सकता है और उसके पास Voltageसंपत्ति हो सकती है ,

  • और एक उपवर्ग RechargeableBattery, जो विरासत में मिल सकता है Power()और Voltage, लेकिन यह भी Recharge()घ हो सकता है ।

ध्यान दें कि आप RechargeableBatteryकक्षा के एक उदाहरण को किसी भी विधि के पैरामीटर के रूप में पारित कर सकते हैं जो Batteryएक तर्क के रूप में स्वीकार करता है । इसे लिस्कोव प्रतिस्थापन सिद्धांत कहा जाता है , जो कि पांच SOLID सिद्धांतों में से एक है। इसी तरह, वास्तविक जीवन में, अगर मेरे एमपी 3 प्लेयर दो एए बैटरी स्वीकार करते हैं, तो मैं उन्हें दो रिचार्जेबल एए बैटरी द्वारा स्थानापन्न कर सकता हूं।

ध्यान दें कि कभी-कभी यह निर्धारित करना मुश्किल होता है कि आपको किसी चीज़ के बीच अंतर का प्रतिनिधित्व करने के लिए किसी क्षेत्र या उपवर्ग का उपयोग करने की आवश्यकता है या नहीं। उदाहरण के लिए, यदि आपको AA, AAA और 9-वोल्ट बैटरी संभालनी है, तो क्या आप तीन उपवर्ग बनाएंगे या एक एनम का उपयोग करेंगे? पृष्ठ 232, मार्टिन फाउलर के रिफैक्टरिंग में, "फ़ील्ड्स के साथ उपवर्ग को बदलें" आपको कुछ विचार दे सकता है और एक से दूसरे में कैसे जाना है।

आपके उदाहरण में, Karlऔर Johnकुछ भी विस्तारित न करें, न ही वे कोई अतिरिक्त मूल्य प्रदान करते हैं: आपके पास Personसीधे कक्षा का उपयोग करके समान कार्यक्षमता हो सकती है । बिना अतिरिक्त मूल्य वाले कोड की अधिक पंक्तियाँ होना कभी अच्छा नहीं होता है।

एक व्यापार के मामले का एक उदाहरण

संभवतः एक व्यावसायिक मामला क्या हो सकता है जहां यह वास्तव में किसी विशिष्ट व्यक्ति के लिए उपवर्ग बनाने के लिए समझ में आता है?

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

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

इस तरह के आवेदन के लिए सबसे खराब मॉडल वर्ग है जैसे:

          वर्ग आरेख हेलेन, थॉमस, मैरी और जिमी कक्षाएं और उनके सामान्य माता-पिता को दर्शाता है: सार व्यक्ति वर्ग।

क्योंकि कोड दोहराव बहुत जल्दी पैदा होगा। यहां तक ​​कि चार कर्मचारियों के बहुत मूल उदाहरण में, आप थॉमस और मैरी कक्षाओं के बीच कोड की नकल करेंगे। यह आपको एक सामान्य अभिभावक वर्ग बनाने के लिए प्रेरित करेगा Programmer। चूंकि आपके पास कई अकाउंटेंट भी हो सकते हैं, आप शायद Accountantक्लास भी बनाएंगे ।

          वर्ग आरेख तीन बच्चों के साथ एक सार व्यक्ति को दर्शाता है: सार लेखाकार, एक सार प्रोग्रामर, और जिमी।  लेखाकार के पास एक उपवर्ग हेलन है, और प्रोग्रामर के दो उपवर्ग हैं: थॉमस और मैरी।

अब, आप ध्यान देते हैं कि कक्षा Helenका होना बहुत उपयोगी नहीं है, साथ ही साथ रखना Thomasऔर Mary: आपका अधिकांश कोड ऊपरी स्तर पर वैसे भी काम करता है - लेखाकार, प्रोग्रामर और जिमी के स्तर पर। एसवीएन सर्वर परवाह नहीं करता है अगर यह थॉमस या मैरी है जिसे लॉग तक पहुंचने की आवश्यकता है - यह केवल यह जानने की जरूरत है कि यह प्रोग्रामर है या अकाउंटेंट है।

if (person is Programmer)
{
    this.AccessGranted = true;
}

इसलिए आप उन कक्षाओं को हटा दें जिन्हें आप उपयोग नहीं करते हैं:

          कक्षा के आरेख में लेखाकार, प्रोग्रामर और जिमी उपवर्ग शामिल हैं, जिनके सामान्य अभिभावक वर्ग: सार व्यक्ति।

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

if (person is Jimmy)
{
    this.GiveUnrestrictedAccess(); // Because Jimmy should do whatever he wants.
}
else if (person is Programmer)
{
    this.AccessGranted = true;
}

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


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

3
लघु उत्तर पहले पोस्ट किए जाते हैं। पहले के पोस्टों को अधिक वोट मिलते हैं।
टिम बी।

1
@ टिम: मैं आमतौर पर मध्यम आकार के उत्तरों के साथ शुरू करता हूं, और फिर उन्हें बहुत पूरा होने के लिए संपादित करता हूं (यहां एक उदाहरण दिया गया है, यह देखते हुए कि लगभग पंद्रह संशोधन थे, केवल चार दिखाए जा रहे थे)। मैंने देखा कि अब समय के साथ इसका उत्तर बन जाता है, इसे प्राप्त होने वाले कम उत्थान; इसी तरह का सवाल जो कम रहता है, वह और अधिक आकर्षित करता है।
आर्सेनी मूरज़ेंको 18

@DocBrown से सहमत हैं। उदाहरण के लिए, एक अच्छा जवाब " व्यवहार के लिए उपवर्ग , सामग्री के लिए नहीं " जैसा कुछ कहेगा , और कुछ संदर्भ को संदर्भित करेगा जो मैं इस टिप्पणी में नहीं करूंगा।
user949300

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

15

यह इस तरह के वर्ग संरचना का उपयोग करने के लिए केवल विवरणों को बदलने के लिए मूर्खतापूर्ण है जो स्पष्ट रूप से एक उदाहरण पर समझौता योग्य क्षेत्र होना चाहिए। लेकिन यह आपके उदाहरण के लिए विशेष रूप से है।

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

अंतर यह है कि आप उस वर्ग द्वारा प्रतिनिधित्व की जाने वाली संस्थाओं से भिन्नता की अपेक्षा कैसे करते हैं। लोगों को लगभग हमेशा आने और जाने के लिए माना जाता है, और उपयोगकर्ताओं के साथ काम करने वाले लगभग हर गंभीर एप्लिकेशन से यह अपेक्षा की जाती है कि वे रन-टाइम पर उपयोगकर्ताओं को जोड़ने और हटाने में सक्षम हों। लेकिन अगर आप अलग-अलग एन्क्रिप्शन एल्गोरिदम जैसी चीजों को मॉडल करते हैं, तो एक नए का समर्थन करना वैसे भी एक बड़ा बदलाव है, और यह एक नए वर्ग का आविष्कार करने के लिए समझ में आता है, जिसका myName()तरीका एक अलग स्ट्रिंग लौटाता है (और जिसका perform()तरीका संभवतः कुछ अलग करता है)।


12

जब उदाहरण पर्याप्त हैं तो मैं नई कक्षाएं क्यों बनाऊंगा?

ज्यादातर मामलों में, आप नहीं करेंगे। आपका उदाहरण वास्तव में एक अच्छा मामला है जहां यह व्यवहार वास्तविक मूल्य नहीं जोड़ता है।

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

हालाँकि, somtimes, यदि आपके पास केवल एक या दो विशेष कॉन्फ़िगरेशन होंगे जो अक्सर पूरे कोड में उपयोग किए जाते हैं, तो यह कभी-कभी अधिक सुविधाजनक और कम समय होता है जो एक जटिल निर्माणकर्ता के माता-पिता को उपवर्गित करता है। ऐसे विशेष मामलों में, मैं इस तरह के दृष्टिकोण के साथ कुछ भी गलत नहीं देख सकता। आइए इसे कंस्ट्रक्टर करी जे / के कहते हैं


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

@BenAaronson जब तक संपत्ति का व्यवहार ही नहीं बदला है, आप OCP का उल्लंघन नहीं करते हैं, लेकिन यहां वे करते हैं। बेशक आप उस संपत्ति का उपयोग उसके आंतरिक कामकाज में कर सकते हैं। लेकिन आपको मौजूदा व्यवहार में परिवर्तन नहीं करना चाहिए! आपको केवल व्यवहार का विस्तार करना चाहिए, इसे विरासत के साथ नहीं बदलना चाहिए। बेशक, हर नियम के अपवाद हैं।
फाल्कन

1
तो आभासी सदस्यों का कोई भी उपयोग OCP उल्लंघन है?
बेन एरनसन

3
@ फाल्कन को दोहराए जाने वाले जटिल कंस्ट्रक्टर कॉल्स से बचने के लिए एक नया वर्ग प्राप्त करने की आवश्यकता नहीं है। बस सामान्य मामलों के लिए कारखानों का निर्माण करें और छोटे बदलावों को मापें।
कीन

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

8

यदि यह अभ्यास की सीमा है, तो मैं मानता हूं कि यह एक बुरा अभ्यास है।

अगर जॉन और कार्ल का व्यवहार अलग है, तो चीजें थोड़ी बदल जाती हैं। यह हो सकता है कि personयह एक तरीका है cleanRoom(Room room)जहां यह पता चलता है कि जॉन एक महान रूममेट है और बहुत प्रभावी ढंग से साफ करता है, लेकिन कार्ल नहीं है और कमरे को बहुत साफ नहीं करता है।

इस मामले में, यह समझ में आता है कि परिभाषित व्यवहार के साथ उन्हें अपना उपवर्ग होना चाहिए। एक ही चीज़ को प्राप्त करने के लिए बेहतर तरीके हैं (उदाहरण के लिए, एक CleaningBehaviorवर्ग), लेकिन कम से कम इस तरह से ओओ सिद्धांतों का भयानक उल्लंघन नहीं है।


कोई अलग व्यवहार नहीं, बस अलग डेटा। धन्यवाद।
इग्नासियो सोलर गार्सिया

6

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

जावा उदाहरण:

public enum Person
{
    KARL("Karl"),
    JOHN("John")

    private final String name;

    private Person(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return this.name;
    }
}

6

बहुत से लोगों ने पहले ही जवाब दे दिया। सोचा था कि मैं अपना निजी दृष्टिकोण दूंगा।


एक बार मैंने एक ऐप पर काम किया (और अभी भी है) जो संगीत बनाता है।

एप्लिकेशन एक सार था Scale: कई उपवर्गों के साथ वर्ग CMajor, DMinorआदि, Scaleतो कुछ इस तरह देखा:

public abstract class Scale {
    protected Note[] notes;
    public Scale() {
        loadNotes();
    }
    // .. some other stuff ommited
    protected abstract void loadNotes(); /* subclasses put notes in the array
                                          in this method. */
}

संगीत जनरेटर ने Scaleसंगीत उत्पन्न करने के लिए एक विशिष्ट उदाहरण के साथ काम किया । उपयोगकर्ता सूची से एक पैमाने का चयन करेगा, जिससे संगीत उत्पन्न किया जा सके।

एक दिन, मेरे दिमाग में एक अच्छा विचार आया: क्यों न उपयोगकर्ता को अपना पैमाना बनाने की अनुमति दें? उपयोगकर्ता सूची से नोट्स का चयन करेगा, एक बटन दबाएगा, और सूची में उपलब्ध तराजू में एक नया पैमाना जोड़ा जाएगा।

लेकिन मैं ऐसा करने में सक्षम नहीं था। ऐसा इसलिए था क्योंकि सभी तराजू पहले से ही संकलित समय पर सेट हैं - क्योंकि उन्हें कक्षाओं के रूप में व्यक्त किया गया है। फिर इसने मुझे मारा:

'सुपरक्लास और उपवर्ग' के संदर्भ में अक्सर सोचना सहज है। लगभग सभी चीजें इस प्रणाली के माध्यम से व्यक्त की जा सकती हैं: सुपरक्लास Personऔर उपवर्ग Johnऔर Mary; सुपरक्लास Carऔर उपवर्ग Volvoऔर Mazda; सुपरक्लास Missileऔर उपवर्ग SpeedRocked, LandMineऔर TrippleExplodingThingy

इस तरह से सोचना बहुत स्वाभाविक है, विशेष रूप से ओओ के लिए अपेक्षाकृत नए व्यक्ति के लिए।

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

यह टेम्पलेट को भरने के लिए उपवर्ग का काम नहीं है। यह वस्तु का काम है। उपवर्ग का काम वास्तविक कार्यक्षमता जोड़ना या टेम्पलेट का विस्तार करना है

और यही कारण है कि मुझे एक ठोस Scaleवर्ग बनाया जाना चाहिए , एक Note[]क्षेत्र के साथ , और वस्तुओं को इस टेम्पलेट में भरने दें ; संभवतः निर्माता या कुछ के माध्यम से। और आखिरकार, इसलिए मैंने किया।

हर बार जब आप एक डिजाइन टेम्पलेट (उदाहरण के लिए, एक खाली एक कक्षा में Note[]सदस्य है कि जरूरतों को भरे जाने के लिए, या एक String nameक्षेत्र है कि जरूरतों को एक मूल्य आवंटित करने के लिए), याद रखें कि यह टेम्पलेट को भरने के लिए इस वर्ग की वस्तुओं के काम है ( या संभवतः इन वस्तुओं को बनाने वाले)। उपवर्गों को कार्यक्षमता जोड़ना है, न कि टेम्प्लेट भरना।


आपको "सुपरक्लास Person, उपवर्गों " Johnऔर Mary"इस तरह की" प्रणाली बनाने का लालच दिया जा सकता है , जैसे आपने किया, क्योंकि आपको औपचारिकता पसंद है।

इस तरह, आप बस के Person p = new Mary()बजाय कह सकते हैं Person p = new Person("Mary", 57, Sex.FEMALE)। यह चीजों को अधिक संगठित, और अधिक संरचित बनाता है। लेकिन जैसा कि हमने कहा, डेटा के हर संयोजन के लिए एक नया वर्ग बनाना अच्छा तरीका नहीं है, क्योंकि यह कुछ भी नहीं के लिए कोड को ब्लॉट करता है और आपको रनटाइम क्षमताओं के मामले में सीमित करता है।

तो यहाँ एक समाधान है: एक मूल कारखाने का उपयोग करें, यहां तक ​​कि एक स्थिर भी हो सकता है। इस तरह:

public final class PersonFactory {
    private PersonFactory() { }

    public static Person createJohn(){
        return new Person("John", 40, Sex.MALE);
    }

    public static Person createMary(){
        return new Person("Mary", 57, Sex.FEMALE);
    }

    // ...
}

इस तरह, आप आसानी से 'प्रीसेट्स' को 'प्रोग्राम के साथ आओ' का उपयोग कर सकते हैं, जैसे: Person mary = PersonFactory.createMary()लेकिन, आप नए व्यक्तियों को गतिशील रूप से डिजाइन करने का अधिकार भी रखते हैं, उदाहरण के लिए उस मामले में जिसे आप उपयोगकर्ता को ऐसा करने की अनुमति देना चाहते हैं। । उदाहरण के लिए:

// .. requesting the user for input ..
String name = // user input
int age = // user input
Sex sex = // user input, interpreted
Person newPerson = new Person(name, age, sex);

या इससे भी बेहतर: ऐसा कुछ करें:

public final class PersonFactory {
    private PersonFactory() { }

    private static Map<String, Person> persons = new HashMap<>();
    private static Map<String, PersonData> personBlueprints = new HashMap<>();

    public static void addPerson(Person person){
        persons.put(person.getName(), person);
    }

    public static Person getPerson(String name){
        return persons.get(name);
    }

    public static Person createPerson(String blueprintName){
        PersonData data = personBlueprints.get(blueprintName);
        return new Person(data.name, data.age, data.sex);
    }

    // .. or, alternative to the last method
    public static Person createPerson(String personName){
        Person blueprint = persons.get(personName);
        return new Person(blueprint.getName(), blueprint.getAge(), blueprint.getSex());
    }

}

public class PersonData {
    public String name;
    public int age;
    public Sex sex;

    public PersonData(String name, int age, Sex sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}

मैं आपे से बाहर हो गया। मुझे लगता है कि आपको विचार समझ आ गया है।


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

आपको डेटा के हर संभव संयोजन के लिए एक नया वर्ग नहीं बनाना चाहिए। (ठीक उसी तरह जैसे मुझे Scaleहर संभव संयोजन के लिए एक नया उपवर्ग नहीं बनाना चाहिए Note)।

एक दिशानिर्देश: जब भी आप एक नया उपवर्ग बनाते हैं, तो विचार करें कि क्या यह कोई नई कार्यक्षमता जोड़ता है जो सुपरक्लास में मौजूद नहीं है। यदि उस प्रश्न का उत्तर "नहीं" है, तो हो सकता है कि आप सुपरक्लास के 'खाके' को भरने की कोशिश कर रहे हों, जिस स्थिति में सिर्फ एक वस्तु का निर्माण करें। (और संभवतः जीवन को आसान बनाने के लिए 'प्रीसेट' के साथ एक कारखाना)।

उम्मीद है की वो मदद करदे।


यह एक उत्कृष्ट उदाहरण है, बहुत-बहुत धन्यवाद।
इग्नासियो सोलर गार्सिया

@ मुझे खुशी है कि मैं मदद कर सकता हूँ।
अवीव कोहन

2

यह यहाँ 'उदाहरण होना चाहिए' का एक अपवाद है - हालांकि थोड़ा चरम पर।

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


2

कोड डुप्लिकेट होना एक बुरा व्यवहार माना जाता है

यह कम से कम आंशिक रूप से है क्योंकि कोड की लाइनें और इसलिए कोडबेस का आकार रखरखाव की लागत और दोषों से संबंधित है

इस विशेष विषय पर मेरे लिए प्रासंगिक सामान्य ज्ञान तर्क है:

1) अगर मुझे इसे बदलने की आवश्यकता होती, तो मुझे कितने स्थानों की यात्रा करने की आवश्यकता होती? यहां कम बेहतर है।

2) क्या इस तरह से ऐसा करने का कोई कारण है? आपके उदाहरण में - ऐसा नहीं हो सकता है - लेकिन कुछ उदाहरणों में ऐसा करने के कुछ कारण हो सकते हैं। एक मैं सोच सकता हूं कि मेरे सिर के ऊपर कुछ फ्रेम में हैं जैसे कि शुरुआती ग्रिल्स जहां वंशानुक्रम जरूरी नहीं कि GORM के कुछ प्लगइन्स के साथ अच्छी तरह से खेलें। बहुत कम।

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


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

बिंदु # 2 देखें। निश्चित रूप से कारण हैं, कभी-कभार। इसलिए आपको किसी के कोड को निकालने से पहले पूछना होगा।
dcgregorya

0

एक उपयोग का मामला है: एक नियमित ऑब्जेक्ट के रूप में फ़ंक्शन या विधि का संदर्भ बनाना।

आप इसे जावा GUI कोड में देख सकते हैं:

ActionListener a = new ActionListener() {
    public void actionPerformed(ActionEvent arg0) {
        /* ... */
    }
};

संकलक आपको एक नया अनाम उपवर्ग बनाकर यहाँ मदद करता है।

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