कंस्ट्रक्टर-केवल उपवर्ग: यह एक विरोधी पैटर्न है?


37

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

अपने अंतर्ज्ञान को और अधिक ध्यान से रखने के लिए, मुझे लगता है कि अगर मेरे पास एक उपवर्ग है जो एक मूल वर्ग का विस्तार करता है, लेकिन एकमात्र कोड जो उपवर्ग ओवरराइड करता है वह एक निर्माता है (हाँ, मुझे पता है कि कंस्ट्रक्टर आम तौर पर "ओवरराइड" नहीं करते हैं, मेरे लिए सहन करते हैं), फिर क्या वास्तव में जरूरत थी एक सहायक विधि थी।

उदाहरण के लिए, इसे कुछ हद तक वास्तविक जीवन वर्ग पर विचार करें:

public class DataHelperBuilder
{
    public string DatabaseEngine { get; set; }
    public string ConnectionString { get; set; }

    public DataHelperBuilder(string databaseEngine, string connectionString)
    {
        DatabaseEngine = databaseEngine;
        ConnectionString = connectionString;
    }

    // Other optional "DataHelper" configuration settings omitted

    public DataHelper CreateDataHelper()
    {
        Type dataHelperType = DatabaseEngineTypeHelper.GetType(DatabaseEngine);
        DataHelper dh = (DataHelper)Activator.CreateInstance(dataHelperType);
        dh.SetConnectionString(ConnectionString);

        // Omitted some code that applies decorators to the returned object
        // based on omitted configuration settings

        return dh;
    }
}

उनका दावा है कि इस तरह एक उपवर्ग होना पूरी तरह से उचित होगा:

public class SystemDataHelperBuilder
{
    public SystemDataHelperBuilder()
        : base(Configuration.GetSystemDatabaseEngine(),
               Configuration.GetSystemConnectionString())
    {
    }
 }

तो, सवाल:

  1. डिजाइन पैटर्न के बारे में बात करने वाले लोगों में, इनमें से कौन सा अंतर्ज्ञान सही है? क्या उप-संरचना को एक विरोधी पैटर्न के ऊपर वर्णित किया गया है?
  2. यदि यह एक विरोधी पैटर्न है, तो इसका नाम क्या है?

मैं माफी माँगता हूँ अगर यह एक आसानी से googleable जवाब हो गया है; Google पर मेरी खोजों ने ज्यादातर टेलीस्कोपिंग कंस्ट्रक्टर विरोधी पैटर्न के बारे में जानकारी लौटा दी और वास्तव में मैं क्या देख रहा था।


2
मैं "हेल्पर" शब्द को एक एंटीपार्टर्न मानता हूं। यह किसी चीज़ और व्हाट्सएट के निरंतर संदर्भों के साथ एक निबंध को पढ़ने जैसा है। कहो क्या है । क्या यह एक कारखाना है? निर्माता? मेरे लिए यह एक आलसी विचार प्रक्रिया की कमी है, और यह एकल जिम्मेदारी सिद्धांत के उल्लंघन को प्रोत्साहित करता है, क्योंकि एक उचित शब्दार्थ इसे निर्देशित करेगा। मैं अन्य मतदाताओं से सहमत हूं, और आपको @ lxrec के उत्तर को स्वीकार करना चाहिए। फ़ैक्टरी विधि के लिए उपवर्ग बनाना पूरी तरह से व्यर्थ है, जब तक कि आप उपयोगकर्ताओं को दस्तावेज़ में निर्दिष्ट सही तर्कों को पारित करने के लिए भरोसा नहीं कर सकते। किस स्थिति में, नए उपयोगकर्ता प्राप्त करें।
हारून हॉल

मैं @ Ixrec के उत्तर से बिल्कुल सहमत हूं। आखिरकार, उनका जवाब कहता है कि मैं बिल्कुल सही था और मेरा सहकर्मी गलत था। ;-) लेकिन गंभीरता से, यही कारण है कि मुझे यह स्वीकार करने में अजीब लगा; मुझे लगा कि मुझ पर पक्षपात का आरोप लगाया जा सकता है। लेकिन मैं प्रोग्रामर StackExchange के लिए नया हूँ; अगर मैं आश्वस्त था कि मैं इसे शिष्टाचार का उल्लंघन नहीं मानूंगा, तो मैं इसे स्वीकार करने को तैयार हूँ।
मुश्किल से KnowEm

1
नहीं, आपसे यह अपेक्षा की जाती है कि आप जिस उत्तर को सबसे मूल्यवान समझते हैं, उसे स्वीकार करें। एक समुदाय को लगता है कि सबसे अधिक मूल्यवान है अब तक Ixrec द्वारा 3 से 1. से अधिक है। इस प्रकार वे आपसे इसे स्वीकार करने की उम्मीद करेंगे। इस समुदाय में, एक प्रश्नकर्ता द्वारा गलत उत्तर को स्वीकार करने में बहुत कम निराशा व्यक्त की जाती है, लेकिन प्रश्न पूछने वालों में व्यक्त हताशा का एक बड़ा कारण यह है कि एक उत्तर को कभी स्वीकार नहीं करते हैं। ध्यान दें कि कोई भी यहां स्वीकृत उत्तर के बारे में शिकायत नहीं कर रहा है, इसके बजाय वे मतदान के बारे में शिकायत करते हैं, जो खुद को सही प्रतीत होता है: stackoverflow.com/q/2052390/541136
हारून हॉल

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

जवाबों:


54

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

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


2
फैक्ट्री मेथड हालांकि आपको अपने कोडबेस में कुछ व्यवहारों (तर्कों द्वारा शासित) को लागू नहीं करने देते। और कभी-कभी यह स्पष्ट रूप से एनोटेट करने के लिए उपयोगी होता है कि यह वर्ग / विधि / क्षेत्र SystemDataHelperBuilderविशेष रूप से लेता है ।
तेलस्टाइन

3
आह, वर्ग बनाम आयत तर्क बिल्कुल वही था जिसकी मुझे तलाश थी, मुझे लगता है। धन्यवाद!
हार्डलीकॉन्मे

7
यदि वे अपरिवर्तनीय हैं, तो निश्चित रूप से, वर्ग का आयत का उपवर्ग होना ठीक हो सकता है। आपको वास्तव में एलएसपी को देखना होगा।
डेविड कॉनरेड

10
वर्ग / आयत "समस्या" के बारे में बात यह है कि ज्यामितीय आकार अपरिवर्तनीय हैं। आप हमेशा एक वर्ग का उपयोग कर सकते हैं जहां कोई आयत समझ में आता है, लेकिन आकार बदलना कुछ वर्ग या आयत नहीं है।
डोभाल

3
@ न्हा एलएसपी = लिसकोव प्रतिस्थापन सिद्धांत
Ixrec

16

इनमें से कौन सा अंतर्ज्ञान सही है?

आपका सहकर्मी सही है (मानक प्रकार प्रणाली मानकर)।

इसके बारे में सोचो, कक्षाएं संभावित कानूनी मूल्यों का प्रतिनिधित्व करती हैं। यदि क्लास Aमें एक बाइट फ़ील्ड है F, तो आप यह सोच सकते हैं कि Aइसमें 256 कानूनी मूल्य हैं, लेकिन यह अंतर्ज्ञान गलत है। A"मानों के हर क्रमपरिवर्तन" को " F0-255 फ़ील्ड होना चाहिए" को प्रतिबंधित कर रहा है ।

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

या यह सोचने के लिए एक और तरीका है, मान लेते हैं कि Aउप-प्रकारों का एक समूह था: B, C, और D। एक प्रकार का चर Aइनमें से कोई भी उपप्रकार हो सकता है, लेकिन प्रकार Bका एक चर अधिक विशिष्ट है। यह (अधिकांश प्रकार की प्रणालियों में) a Cया a नहीं हो सकता है D

क्या यह एक विरोधी पैटर्न है?

Enh? विशेष वस्तुओं का होना उपयोगी है और कोड के लिए स्पष्ट रूप से हानिकारक नहीं है। उप-प्रकार का उपयोग करके परिणाम प्राप्त करना शायद थोड़ा संदिग्ध है, लेकिन आपके निपटान में आपके पास कौन से उपकरण हैं, यह निर्भर करता है। बेहतर उपकरणों के साथ भी यह कार्यान्वयन सरल, सीधा और मजबूत है।

मैं इसे एक विरोधी प्रतिमान नहीं मानूंगा क्योंकि यह किसी भी स्थिति में स्पष्ट रूप से गलत और बुरा नहीं है।


5
"अधिक नियमों का अर्थ है कम संभव मान, अधिक विशिष्ट अर्थ।" मैं वास्तव में इसका पालन नहीं करता हूं। टाइप में byte and byteनिश्चित रूप से सिर्फ टाइप से अधिक मान हैं byte; 256 बार के रूप में कई। एक तरफ, मुझे नहीं लगता कि आप तत्वों की संख्या के साथ नियमों को भ्रमित कर सकते हैं (या कार्डिनैलिटी यदि आप सटीक होना चाहते हैं)। जब आप अनंत सेटों पर विचार करते हैं तो यह टूट जाता है। पूर्णांक के रूप में कई सम संख्याएँ हैं, लेकिन यह जानते हुए भी कि एक संख्या अभी भी एक प्रतिबंध है / मुझे केवल पूर्णांक जानने से अधिक जानकारी देती है! प्राकृतिक संख्याओं के लिए भी यही कहा जा सकता है।
डोभाल

6
@Telastyn हम ऑफ़-टॉपिक हो रहे हैं, लेकिन यह साबित होता है कि पूर्णांकों के समुच्चय के कार्डिनैलिटी (शिथिल, "आकार") सभी पूर्णांकों के सेट, या यहां तक ​​कि सभी परिमेय संख्याओं के समान है। यह वास्तव में अच्छा सामान है। Math.grinnell.edu/~miletijo/museum/infinite.html
हार्डलीकॉन्मे

2
सेट सिद्धांत बहुत अचूक है। आप पूर्णांक और ईवेंस को एक-से-एक पत्राचार में रख सकते हैं (जैसे फ़ंक्शन का उपयोग करना n -> 2n)। यह हमेशा संभव नहीं; आप पूर्णांक को वास्तविक में मैप नहीं कर सकते हैं, इसलिए वास्तविक का पूर्णांक पूर्णांक से "बड़ा" होता है। लेकिन आप सभी वास्तविकों के सेट पर वास्तविक (वास्तविक) अंतराल [0, 1] को मैप कर सकते हैं, जिससे उन्हें समान "आकार" मिलता है। सबटाइम्स को "हर तत्व का तत्व" के रूप में परिभाषित किया गया Aहै B"ठीक है क्योंकि एक बार जब आपके सेट अनंत हो जाते हैं, तो यह मामला हो सकता है कि वे एक ही कार्डिनैलिटी हैं लेकिन अलग-अलग तत्व हैं।
डोभाल

1
हाथ में विषय से अधिक संबंधित, जो उदाहरण आप देते हैं वह एक बाधा है, जो वस्तु-उन्मुख प्रोग्रामिंग के संदर्भ में, वास्तव में -functionality- एक अतिरिक्त क्षेत्र के संदर्भ में। मैं उपवर्गों के बारे में बात कर रहा हूं जो कार्यक्षमता का विस्तार नहीं करते हैं - जैसे सर्कल-एलिप्से समस्या।
हार्डलीकॉन्मे

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

12

नहीं, यह एक विरोधी पैटर्न नहीं है। मैं इसके लिए कई व्यावहारिक उपयोग के मामलों के बारे में सोच सकता हूं:

  1. यदि आप संकलन समय का उपयोग करना चाहते हैं, तो सुनिश्चित करें कि वस्तुओं का संग्रह केवल एक विशेष उपवर्ग के अनुरूप हो। उदाहरण के लिए, यदि आपके पास MySQLDaoऔर SqliteDaoआपके सिस्टम में है, लेकिन किसी कारण से आप यह सुनिश्चित करना चाहते हैं कि एक संग्रह में केवल एक स्रोत से डेटा होता है, यदि आप उप-वर्ग का उपयोग करते हैं जैसा कि आप वर्णन करते हैं कि आपके पास कंपाइलर इस विशेष शुद्धता को सत्यापित कर सकता है। दूसरी ओर, यदि आप डेटा स्रोत को एक फ़ील्ड के रूप में संग्रहीत करते हैं, तो यह रन-टाइम चेक बन जाएगा।
  2. मेरे वर्तमान एप्लिकेशन में AlgorithmConfiguration+ ProductClassऔर के बीच एक से एक संबंध है AlgorithmInstance। दूसरे शब्दों में, यदि आप गुण फ़ाइल में कॉन्फ़िगर FooAlgorithmकरते हैं , तो आप ProductClassकेवल FooAlgorithmउस उत्पाद वर्ग के लिए एक प्राप्त कर सकते हैं । FooAlgorithmकिसी दिए गए के लिए दो एस प्राप्त करने का एकमात्र तरीका ProductClassएक उपवर्ग बनाना है FooBarAlgorithm। यह ठीक है, क्योंकि यह गुण फ़ाइल का उपयोग करना आसान बनाता है (गुण फ़ाइल में एक खंड में कई अलग-अलग कॉन्फ़िगरेशन के लिए सिंटैक्स की कोई आवश्यकता नहीं है), और यह बहुत दुर्लभ है किसी दिए गए उत्पाद वर्ग के लिए एक से अधिक उदाहरण होंगे।
  3. @ तेलस्तीन का जवाब एक और अच्छा उदाहरण देता है।

निचला रेखा: ऐसा करने में वास्तव में कोई बुराई नहीं है। एक विरोधी पैटर्न को परिभाषित किया गया है:

एक एंटी-पैटर्न (या एंटीपैटर्न) एक आवर्ती समस्या के लिए एक सामान्य प्रतिक्रिया है जो आमतौर पर अप्रभावी होती है और जोखिम अत्यधिक प्रतिशोधी होते हैं।

यहां अत्यधिक उल्टा होने का कोई जोखिम नहीं है, इसलिए यह एक विरोधी पैटर्न नहीं है।


2
हाँ, मुझे लगता है कि अगर मुझे फिर से सवाल का जवाब देना पड़े, तो मैं कहूंगा "कोड गंध।" यह युवा डेवलपर्स की अगली पीढ़ी को इससे बचने के लिए चेतावनी देने के लिए पर्याप्त नहीं है, लेकिन यह कुछ ऐसा है जिसे अगर आप देखते हैं, तो यह संकेत दे सकता है कि अतिव्यापी डिजाइन में समस्या है, लेकिन अंततः भी सही हो सकती है।
मुश्किल से

पॉइंट 1 निशाने पर सही है। मैं वास्तव में बिंदु 2 को नहीं समझता था, लेकिन मुझे यकीन है कि यह उतना ही अच्छा है ... :)
फिल

9

अगर कुछ एक पैटर्न है या एक antipattern क्या भाषा और पर्यावरण आप में लिख रहे हैं पर काफी निर्भर करता है। उदाहरण के लिए, forछोरों एक पैटर्न हैं विधानसभा, सी, और इसी तरह की भाषाओं में और तुतलाना में एक antipattern।

मैं आपको कुछ कोड की एक कहानी बताता हूं जो मैंने बहुत पहले लिखी थी ...

यह LPC नामक भाषा में था और एक खेल में कास्टिंग मंत्र के लिए एक रूपरेखा लागू की। आपके पास एक स्पेल सुपरक्लास था, जिसमें कुछ जांचों को संभालने वाले कॉम्बैट मंत्रों का एक उपवर्ग था, और फिर सिंगल टारगेट डायरेक्ट डैमेज मंत्रों के लिए एक उपवर्ग था, जिसे बाद में व्यक्तिगत मंत्रों - मैजिक मिसाइल, लाइटेट बोल्ट और लाइक से उप-वर्गित किया गया था।

एलपीसी ने कैसे काम किया इसकी प्रकृति यह थी कि आपके पास एक मास्टर ऑब्जेक्ट था जो एक सिंगलटन था। इससे पहले कि आप 'eww सिंगलटन' जाओ - यह था और यह "eww" बिल्कुल नहीं था। एक ने मंत्र की प्रतियां नहीं बनाईं, बल्कि मंत्रों में स्थिर तरीकों से (प्रभावी) तरीके से आह्वान किया। मैजिक मिसाइल के लिए कोड जैसा दिखता था:

inherit "spells/direct";

void init() {
  ::init();
  damage = 10;
  cost = 3;
  delay = 1.0;
  caster_message = "You cast a magic missile at ${target}";
  target_message = "You are hit with a magic missile cast by ${caster}";
}

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

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

यह कोई बुरी बात नहीं है, और यह निश्चित रूप से एक विरोधी पैटर्न नहीं है (और कुछ भाषाओं में यह एक पैटर्न ही हो सकता है)।


2

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

हम ऐसा इसलिए करते हैं क्योंकि अपवाद उनके प्रकार की जाँच करके पकड़े जाते हैं। इस प्रकार, हमें विशेषज्ञता को उस प्रकार में संलग्न करना होगा ताकि कोई व्यक्ति केवल ReadErrorसभी को पकड़े बिना पकड़ सके IOError, क्या उन्हें चाहिए।

आम तौर पर, चीजों के प्रकार की जाँच करना बहुत बुरा रूप है और हम इससे बचने की कोशिश करते हैं। यदि हम इसे टालने में सफल होते हैं, तो टाइप सिस्टम में विशेषज्ञता को व्यक्त करने की कोई आवश्यकता नहीं है।

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

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

हालांकि, विशेष मामलों के लिए प्रकारों का उपयोग करने से कुछ भ्रम हो जाता है, क्योंकि अगर किसी भी तरह से अलग व्यवहार करते हैं ImmutableRectangle(1,1)और अंत में किसी को आश्चर्य होता है कि क्यों और शायद काश ऐसा नहीं होता। अपवाद पदानुक्रमों के विपरीत, आप जाँचते हैं कि आयत एक वर्ग है या नहीं, यह जाँच कर । आपके उदाहरण में, सटीक समान तर्कों के साथ बनाए गए और के बीच एक अंतर है, और जिससे समस्याएँ पैदा होने की संभावना है। इसलिए, "सही" तर्कों के साथ बनाई गई एक वस्तु को वापस करने के लिए एक फ़ंक्शन मुझे सामान्य रूप से सही काम करने लगता है: उपवर्ग "एक ही" चीज़ के दो अलग-अलग प्रतिनिधित्व करता है, और यह केवल तभी मदद करता है जब आप कुछ कर रहे हों आम तौर पर करने की कोशिश नहीं करेंगे।ImmutableSquare(1)height == widthinstanceofSystemDataHelperBuilderDataHelperBuilder

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


मैं इसके लिए उपयोग देख सकता ImmutableSquareMatrix:ImmutableMatrixथा, बशर्ते ImmutableMatrixकि एक ImmutableSquareMatrixसंभव के रूप में अपनी सामग्री को प्रस्तुत करने के लिए पूछने का एक कुशल साधन था । यहां तक ​​कि अगर ImmutableSquareMatrixमूल रूप से एक ImmutableMatrixनिर्माणकर्ता को उस ऊंचाई और चौड़ाई के मिलान की आवश्यकता होती है, और जिसकी AsSquareMatrixविधि बस खुद ही वापस आ जाएगी (उदाहरण के लिए, ImmutableSquareMatrixजो एक ही बैकिंग सरणी को लपेटता है), तो इस तरह के डिजाइन को उन तरीकों के लिए संकलन-समय पैरामीटर सत्यापन की अनुमति होगी जिनके लिए वर्ग की आवश्यकता होती है मैट्रिक्स
supercat

@supercat: अच्छी बात है, और प्रश्नकर्ता के उदाहरण में यदि ऐसे कार्य हैं जिन्हें पारित किया जाना चाहिए SystemDataHelperBuilder, और न ही कोई भी कार्य DataHelperBuilderकरेगा, तो यह उसके लिए एक प्रकार को परिभाषित करने के लिए समझ में आता है (और एक इंटरफ़ेस, यह मानते हुए कि आप डि को उसी तरह से संभालते हैं) । आपके उदाहरण में, कुछ ऑपरेशन हैं एक वर्ग मैट्रिक्स हो सकता है कि एक गैर-वर्ग नहीं होगा, जैसे निर्धारक, लेकिन आपकी बात अच्छी है कि भले ही सिस्टम को उन लोगों की आवश्यकता न हो, जिन्हें आप अभी भी प्रकार से जांचना चाहते हैं। ।
स्टीव जेसोप

... तो मुझे लगता है कि यह पूरी तरह से सच नहीं है कि मैंने क्या कहा, कि "आप जांचते हैं कि क्या आयत एक वर्ग है या height == widthनहीं, यह जाँच कर instanceof"। आप कुछ ऐसा करना पसंद कर सकते हैं जिसे आप सांख्यिकीय रूप से मुखर कर सकें।
स्टीव जेसोप

काश, कोई ऐसा तंत्र होता, जो स्थिर कारखाना विधियों को बनाने के लिए कंस्ट्रक्टर सिंटैक्स जैसी किसी चीज़ की अनुमति देता। अभिव्यक्ति foo=new ImmutableMatrix(someReadableMatrix)का प्रकार someReadableMatrix.AsImmutable()या उससे भी स्पष्ट है ImmutableMatrix.Create(someReadableMatrix), लेकिन बाद के रूप पूर्व की कमी के लिए उपयोगी अर्थ संभावनाएं प्रदान करते हैं; यदि निर्माणकर्ता यह बता सकता है कि मैट्रिक्स वर्गाकार है, तो इसके प्रकार को प्रतिबिंबित करने में सक्षम होना चाहिए जो कोड डाउनस्ट्रीम की आवश्यकता के बजाय क्लीनर हो सकता है जिसे एक नया ऑब्जेक्ट इंस्टेंस बनाने के लिए स्क्वायर मैट्रिक्स की आवश्यकता होती है।
सुपरकाट

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

2

एक उपवर्ग संबंध की सबसे कठोर वस्तु ओरिएंटेड परिभाषा को «इस-ए» के रूप में जाना जाता है। एक वर्ग और एक आयत के पारंपरिक उदाहरण का उपयोग करते हुए, एक वर्ग «is-a» आयत है।

इसके द्वारा, आपको किसी भी स्थिति के लिए उपवर्ग का उपयोग करना चाहिए जहां आपको लगता है कि एक «-ए» आपके कोड के लिए एक सार्थक संबंध है।

एक निर्माणकर्ता के साथ कुछ भी नहीं के साथ एक उपवर्ग के अपने विशिष्ट मामले में, आपको इसे «इस-ए» दृष्टिकोण से विश्लेषण करना चाहिए। यह स्पष्ट है कि एक SystemDataHelperBuilder «is-a» DataHelperBuilder है, इसलिए पहला पास बताता है कि यह एक वैध उपयोग है।

सवाल यह है कि आपको जवाब देना चाहिए कि क्या कोई अन्य कोड इस «-ए» संबंध का लाभ उठाता है। क्या कोई अन्य कोड DataHelperBuilders की सामान्य आबादी से SystemDataHelperBuilders को अलग करने का प्रयास करता है? यदि हां, तो संबंध काफी उचित है, और आपको उपवर्ग रखना चाहिए।

हालांकि, अगर कोई अन्य कोड ऐसा नहीं करता है, तो आपके पास एक रिश्ता है जो एक «ए-ए» संबंध हो सकता है, या इसे एक कारखाने के साथ लागू किया जा सकता है। इस मामले में, आप किसी भी तरह से जा सकते हैं, लेकिन मैं एक «-ए» रिश्ते के बजाय एक कारखाने की सिफारिश करूंगा। किसी अन्य व्यक्ति द्वारा लिखित ऑब्जेक्ट ओरिएंटेड कोड का विश्लेषण करते समय, वर्ग पदानुक्रम जानकारी का एक प्रमुख स्रोत है। यह «is-a» रिश्तों को प्रदान करता है जो उन्हें कोड की समझ बनाने की आवश्यकता होगी। तदनुसार, इस व्यवहार को एक उपवर्ग में डालने से व्यवहार को बढ़ावा मिलता है "अगर कोई व्यक्ति सुपरक्लास के तरीकों में खुदाई करेगा" तो "कुछ हर किसी के माध्यम से दिखेगा इससे पहले कि वे कोड में गोताखोरी शुरू कर दें।" Guido van Rossum का हवाला देते हुए, "कोड को जितना लिखा जाता है, उससे अधिक बार पढ़ा जाता है।" आगामी डेवलपर्स के लिए आपके कोड की घटती पठनीयता भुगतान करने के लिए एक कड़ी कीमत है। मैं इसका भुगतान नहीं करना चाहूंगा, अगर मैं इसके बजाय एक कारखाने का उपयोग कर सकता हूं।


1

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

यह देखते हुए कि आपके द्वारा बनाया गया उपवर्ग शायद गलत नहीं है (क्योंकि मुझे नहीं पता कि वे वास्तव में क्या करते हैं, मैं निश्चित रूप से नहीं कह सकता।) आपको नाजुक आधार वर्ग की समस्या से सावधान रहने की आवश्यकता है, और आपको भी करना होगा। विचार करें कि क्या कोई interfaceआपको लाभान्वित करेगा, लेकिन विरासत के सभी उपयोगों के बारे में यह सच है।


1

मुझे लगता है कि इस प्रश्न का उत्तर देने की कुंजी इस एक, विशेष उपयोग परिदृश्य को देखना है।

कनेक्शन स्ट्रिंग की तरह डेटाबेस कॉन्फ़िगरेशन विकल्पों को लागू करने के लिए इनहेरिटेंस का उपयोग किया जाता है।

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


1

मैं विभिन्न अवधारणाओं को व्यक्त करने के लिए नियमित रूप से केवल उपवर्गों का उपयोग करता हूं।

उदाहरण के लिए, निम्नलिखित वर्ग पर विचार करें:

public class Outputter
{
    private readonly IOutputMethod outputMethod;
    private readonly IDataMassager dataMassager;

    public Outputter(IOutputMethod outputMethod, IDataMassager dataMassager)
    {
        this.outputMethod = outputMethod;
        this.dataMassager = dataMassager;
    }

    public MassageDataAndOutput(string data)
    {
        this.outputMethod.Output(this.dataMassager.Massage(data));
    }
}

फिर हम एक उपवर्ग बना सकते हैं:

public class CapitalizeAndPrintOutputter : Outputter
{
    public CapitalizeAndPrintOutputter()
        : base(new PrintOutputMethod(), new Capitalizer())
    {
    }
}

आप अपने कोड में कहीं भी एक CapitalizeAndPrintOutputter का उपयोग कर सकते हैं और आपको पता है कि यह किस प्रकार का आउटपुट है। इसके अलावा, यह पैटर्न वास्तव में इस वर्ग को बनाने के लिए DI कंटेनर का उपयोग करना बहुत आसान बनाता है। अगर DI कंटेनर को PrintOutputMethod और Capitalizer के बारे में पता है, तो यह आपके लिए CapitalizeAndPrintOutputter को स्वचालित रूप से बना सकता है।

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


1

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

उपवर्ग का एक उदाहरण केवल डाउनकास्ट का उपयोग करके प्रतिष्ठित किया जा सकता है।

अब, यदि आपके पास एक डिज़ाइन है जिसमें DatabaseEngineऔर ConnectionStringगुण उपवर्ग द्वारा फिर से लागू किए गए थे, जो Configurationऐसा करने के लिए एक्सेस किया गया था, तो आपके पास एक बाधा है जो उपवर्ग होने का अधिक अर्थ देता है।

कहा जाता है कि, "एंटी-पैटर्न" मेरे स्वाद के लिए बहुत मजबूत है; यहाँ वास्तव में कुछ भी गलत नहीं है।


0

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

मूल रूप से अगर datahelperbuilder का कोई क्लाइंट systemdatahelperbuilder प्राप्त करता है, तो कुछ भी नहीं टूटेगा। एक अन्य विकल्प यह होगा कि systemdatahelperbuilder डाटाहेल्पीबिल्डर क्लास का एक स्थिर उदाहरण हो।

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