बिल्डर पैटर्न कई तर्कों की "समस्या" को हल नहीं करता है। लेकिन कई तर्क समस्याग्रस्त क्यों हैं?
- वे संकेत देते हैं कि आपकी कक्षा बहुत अधिक काम कर रही है । हालांकि, कई प्रकार हैं जो वैध रूप से कई सदस्य होते हैं जिन्हें समझदारी से समूहीकृत नहीं किया जा सकता है।
- कई आदानों के साथ एक फ़ंक्शन का परीक्षण और समझना घातीय रूप से अधिक जटिल हो जाता है - शाब्दिक रूप से!
- जब भाषा नामित मापदंडों की पेशकश नहीं करती है, तो एक फ़ंक्शन कॉल स्व-दस्तावेजीकरण नहीं है । कई तर्कों के साथ एक फ़ंक्शन कॉल पढ़ना काफी मुश्किल है क्योंकि आपको पता नहीं है कि 7 वें पैरामीटर को क्या करना है। यदि 5 वीं और 6 वीं तर्क को गलती से स्वैप किया गया था, तो आप यह भी ध्यान नहीं देंगे, खासकर यदि आप एक गतिशील रूप से टाइप की गई भाषा में हैं या सब कुछ एक स्ट्रिंग होने के लिए होता है, या जब अंतिम पैरामीटर
true
किसी कारण से होता है।
पैरामीटर नाम का फ़ेकिंग
बिल्डर पैटर्न पतों इन समस्याओं, कई तर्क के साथ समारोह कॉल की अर्थात् रख-रखाव की चिंताओं में से केवल एक * । तो एक फंक्शन कॉल जैसे
MyClass o = new MyClass(a, b, c, d, e, f, g);
बना सकता है
MyClass o = MyClass.builder()
.a(a).b(b).c(c).d(d).e(e).f(f).g(g)
.build();
∗ बिल्डर पैटर्न मूल रूप से मिश्रित वस्तुओं को इकट्ठा करने के लिए एक प्रतिनिधित्व-अज्ञेयवादी दृष्टिकोण के रूप में अभिप्रेत था, जो मापदंडों के लिए सिर्फ नामित तर्कों की तुलना में कहीं अधिक आकांक्षा है। विशेष रूप से, बिल्डर पैटर्न को एक धाराप्रवाह इंटरफ़ेस की आवश्यकता नहीं होती है।
यह थोड़ी अतिरिक्त सुरक्षा प्रदान करता है क्योंकि यह उड़ा देगा यदि आप एक बिल्डर विधि को लागू करते हैं जो मौजूद नहीं है, लेकिन यह अन्यथा आपको कुछ भी नहीं लाता है जो कि कंस्ट्रक्टर कॉल में टिप्पणी नहीं करेगा। इसके अलावा, मैन्युअल रूप से एक बिल्डर बनाने के लिए कोड की आवश्यकता होती है, और अधिक कोड में हमेशा अधिक बग हो सकते हैं।
उन भाषाओं में जहां एक नए मूल्य प्रकार को परिभाषित करना आसान है, मैंने पाया है कि नामित तर्कों को अनुकरण करने के लिए माइक्रोटेपिंग / छोटे प्रकार का उपयोग करना बेहतर है । यह इसलिए नाम दिया गया है क्योंकि प्रकार वास्तव में छोटे हैं, लेकिन आप अंत में बहुत अधिक टाइपिंग करते हैं ;-)
MyClass o = new MyClass(
new MyClass.A(a), new MyClass.B(b), new MyClass.C(c),
new MyClass.D(d), new MyClass.E(e), new MyClass.F(f),
new MyClass.G(g));
जाहिर है, प्रकार के नाम A
, B
, C
, ... आत्म दस्तावेज़ीकृत कर ऐसे नाम हैं जो पैरामीटर, अक्सर एक ही नाम का अर्थ समझाना हो के रूप में आप पैरामीटर चर देना चाहते हैं चाहिए। बिल्डर-फॉर-नेम-दलील मुहावरे की तुलना में, आवश्यक कार्यान्वयन बहुत सरल है, और इस प्रकार कीड़े होने की संभावना कम है। उदाहरण के लिए (जावा-ईश सिंटैक्स के साथ):
class MyClass {
...
public static class A {
public final int value;
public A(int a) { value = a; }
}
...
}
संकलक आपको यह गारंटी देने में मदद करता है कि सभी तर्क प्रदान किए गए थे; एक बिल्डर के साथ आपको गुम तर्कों के लिए मैन्युअल रूप से जांचना होगा, या एक राज्य मशीन को होस्ट भाषा प्रकार सिस्टम में एन्कोड करना होगा - दोनों में संभवतः बग होंगे।
नामित तर्कों को अनुकरण करने के लिए एक और सामान्य दृष्टिकोण है: एक एकल सार पैरामीटर ऑब्जेक्ट जो सभी फ़ील्ड्स को इनिशियलाइज़ करने के लिए इनलाइन क्लास सिंटैक्स का उपयोग करता है। जावा में:
MyClass o = new MyClass(new MyClass.Arguments(){{ argA = a; argB = b; argC = c; ... }});
class MyClass {
...
public static abstract class Arguments {
public int argA;
public String ArgB;
...
}
}
हालांकि, खेतों को भूलना संभव है, और यह एक काफी भाषा-विशिष्ट समाधान है (मैंने जावास्क्रिप्ट, सी #, और सी में उपयोग किया है)।
सौभाग्य से, निर्माता अभी भी सभी तर्कों को मान्य कर सकता है, जो तब नहीं होता है जब आपकी वस्तुओं को आंशिक रूप से निर्मित स्थिति में बनाया जाता है, और उपयोगकर्ता को सेटर या एक init()
विधि के माध्यम से आगे तर्क प्रदान करने की आवश्यकता होती है - जिन्हें कम से कम कोडिंग प्रयास की आवश्यकता होती है, लेकिन बनाते हैं सही प्रोग्राम लिखना अधिक कठिन है ।
इसलिए जब "कई अनाम मानदंड समस्या को बनाए रखने के लिए कोड को मुश्किल बनाते हैं " को संबोधित करने के लिए कई दृष्टिकोण हैं , तो अन्य समस्याएं बनी हुई हैं।
रूट समस्या का सामना करना
उदाहरण के लिए परीक्षण क्षमता की समस्या। जब मैं यूनिट परीक्षण लिखता हूं, तो मुझे परीक्षण डेटा को इंजेक्ट करने की क्षमता की आवश्यकता होती है, और निर्भरता और संचालन को बाहर करने के लिए परीक्षण कार्यान्वयन प्रदान करने के लिए बाहरी दुष्प्रभाव होते हैं। मैं ऐसा नहीं कर सकता, जब आप अपने कंस्ट्रक्टर के भीतर किसी भी क्लास को तुरंत भेज दें। जब तक आपकी कक्षा की जिम्मेदारी अन्य वस्तुओं के निर्माण की नहीं है, तब तक यह किसी भी गैर-तुच्छ वर्गों को तत्काल नहीं करना चाहिए। यह एकल जिम्मेदारी समस्या के साथ हाथ से जाता है। जितना अधिक एक वर्ग की ज़िम्मेदारी होती है, परीक्षण करना उतना ही आसान होता है (और अक्सर उपयोग करने में आसान होता है)।
सबसे आसान और अक्सर सबसे अच्छा तरीका है, निर्माता के लिए पूरी तरह से निर्मित निर्भरता को पैरामीटर के रूप में लेना , हालांकि यह कॉलर को निर्भरता के प्रबंधन की जिम्मेदारी देता है - या तो आदर्श नहीं है, जब तक कि आपके डोमेन मॉडल में निर्भरता स्वतंत्र संस्थाएं नहीं हैं।
इसके बजाय कभी-कभी (अमूर्त) कारखानों या पूर्ण निर्भरता इंजेक्शन ढांचे का उपयोग किया जाता है, हालांकि ये अधिकांश उपयोग के मामलों में ओवरकिल हो सकते हैं। विशेष रूप से, ये केवल तर्कों की संख्या को कम कर देते हैं यदि इनमें से कई तर्क अर्ध-वैश्विक ऑब्जेक्ट या कॉन्फ़िगरेशन मान हैं जो त्वरित इंस्ट्रूमेंटेशन के बीच नहीं बदलते हैं। जैसे अगर पैरामीटर a
और d
वैश्विक-ईश थे, तो हमें मिलेगा
Dependencies deps = new Dependencies(a, d);
...
MyClass o = deps.newMyClass(b, c, e, f, g);
class MyClass {
MyClass(Dependencies deps, B b, C c, E e, F f, G g) {
this.depA = deps.newDepA(b, c);
this.depB = deps.newDepB(e, f);
this.g = g;
}
...
}
class Dependencies {
private A a;
private D d;
public Dependencies(A a, D d) { this.a = a; this.d = d; }
public DepA newDepA(B b, C c) { return new DepA(a, b, c); }
public DepB newDepB(E e, F f) { return new DepB(d, e, f); }
public MyClass newMyClass(B b, C c, E e, F f, G g) {
return new MyClass(deps, b, c, e, f, g);
}
}
आवेदन के आधार पर, यह एक गेम-चेंजर हो सकता है जहां कारखाने के तरीकों में लगभग कोई तर्क नहीं है, क्योंकि सभी निर्भरता प्रबंधक द्वारा प्रदान किए जा सकते हैं, या यह एक बड़ी मात्रा में कोड हो सकता है जो बिना किसी स्पष्ट लाभ के लिए तात्कालिकता को जटिल करता है। इस तरह की फैक्ट्रियां, इंटरफेस को मैप करने से लेकर मापदंडों को प्रबंधित करने के लिए अधिक उपयोगी होती हैं। हालाँकि, यह दृष्टिकोण एक सुंदर धाराप्रवाह इंटरफ़ेस के साथ इसे छिपाने के बजाय बहुत सारे मापदंडों की मूल समस्या को हल करने की कोशिश करता है।