चलो अपने दृष्टिकोण और Reader
दृष्टिकोण के बीच एक सरल, सतही अंतर के साथ शुरू करते हैं, जो कि आपको अब कहीं भी config
पर लटकने की आवश्यकता नहीं है।
type Configured[A] = ConfigSource => A
अब, अगर मैं कभी भी कुछ काम के लिए एक ConfigSource
की जरूरत है, का कहना है कि एक समारोह है कि सूची में वें ग्राहक n 'हो जाता है, मुझे लगता है कि घोषणा कर सकते हैं: चलो आप निम्नलिखित थोड़ा चतुर प्रकार पर्याय परिभाषित मान लीजिए समारोह के रूप में "के लिए कॉन्फ़िगर":
def nthClient(n: Int): Configured[Client] = {
config => config.clients(n)
}
तो हम अनिवार्य रूप से हवा के बाहर एक config
खींच रहे, किसी भी समय हम एक की जरूरत है! निर्भरता इंजेक्शन की तरह बदबू आ रही है, है ना? अब मान लीजिए कि हम सूची में प्रथम, द्वितीय और तृतीय ग्राहकों की उम्र चाहते हैं (यह मानते हुए वे मौजूद):
def ages: Configured[(Int, Int, Int)] =
for {
a0 <- nthClient(0)
a1 <- nthClient(1)
a2 <- nthClient(2)
} yield (a0.age, a1.age, a2.age)
इस के लिए, निश्चित रूप से, आप map
और flatMap
के कुछ उचित परिभाषा की जरूरत है। मैं यहां उसमें नहीं पहुंचूंगा, लेकिन बस यह कहूंगा कि स्कालज़ (या Rúnar's awesome NEScala talk, या Tony's जो आपने पहले ही देखा है) आपको वह सब कुछ देता है जो आपको चाहिए।
यहां महत्वपूर्ण बात यह है कि ConfigSource
निर्भरता और इसके तथाकथित इंजेक्शन अधिकतर छिपे हुए हैं। केवल "संकेत" जिसे हम यहां देख सकते हैं वह है कि ages
(Int, Int, Int)
की बजाय Configured[(Int, Int, Int)]
प्रकार का है। हमें कहीं भी config
स्पष्ट रूप से संदर्भित करने की आवश्यकता नहीं थी।
एक अलग रूप में के रूप में, इस तरह से मैं लगभग हमेशा monads के बारे में सोचना चाहते है: वे अपने प्रभाव तो यह आपके कोड के प्रवाह को प्रदूषित नहीं कर रहा है छिपाने , जबकि स्पष्ट प्रभाव की घोषणा प्रकार हस्ताक्षर में।दूसरे शब्दों में, आपको अपने आप को दोहराने की आवश्यकता नहीं है: आप कहते हैं, "हे, यह फ़ंक्शन प्रभाव X" फ़ंक्शन के रिटर्न प्रकार में है, और इसके साथ गड़बड़ न करें।
इस उदाहरण में, निश्चित रूप से प्रभाव कुछ निश्चित वातावरण से पढ़ना है। एक और मोनैडिक प्रभाव जिसमें आप परिचित हो सकते हैं, त्रुटि-हैंडलिंग शामिल है: हम कह सकते हैं कि Option
आपकी विधि के प्रकार में स्पष्ट त्रुटियों की संभावना बनाते समय त्रुटि-हैंडलिंग तर्क छुपाता है। या, पढ़ने के विपरीत के विपरीत, Writer
मोनैड उस चीज़ को छुपाता है जिसे हम लिख रहे हैं, जबकि इसकी उपस्थिति प्रकार प्रणाली में स्पष्ट है।
अब अंत में, बस के रूप में हम आम तौर पर (जैसे कि एक एक्सएमएल फ़ाइल के रूप में कहीं नियंत्रण की हमारी सामान्य प्रवाह के बाहर,) एक डि ढांचे bootstrap करने की जरूरत है, हम भी इस उत्सुक इकाई bootstrap की जरूरत है।
def run: Configured[Unit] = // ...
यह बहुत सरल किया जा रहा समाप्त होता है: निश्चित रूप से हम इस तरह के रूप में, हमारे कोड के लिए कुछ तार्किक प्रवेश बिंदु होगा के बाद से Configured[A]
समारोह ConfigSource => A
के लिए सिर्फ एक प्रकार पर्याय है, हम बस करने के लिए समारोह लागू कर सकते हैं अपने "पर्यावरण":
run(ConfigFileSource)
// or
run(DatabaseSource)
ता-दा! इसलिए, पारंपरिक जावा-शैली डी दृष्टिकोण के विपरीत, हमारे पास कोई "जादू" नहीं है। एकमात्र जादू, जैसा कि था, हमारे Configured
प्रकार और जिस तरह से यह एक मोनड के रूप में व्यवहार करता है, की परिभाषा में encapsulated है। सबसे महत्वपूर्ण बात यह है कि टाइप सिस्टम हमें ईमानदार रखता है जिसके बारे में "वास्तविक" निर्भरता इंजेक्शन होता है: टाइप Configured[...]
के साथ कुछ भी DI दुनिया में है, और इसके बिना कुछ भी नहीं है। हम इसे पुराने स्कूल डीआई में नहीं पाते हैं, जहां सब कुछ संभावित रूप से जादू द्वारा प्रबंधित किया जाता है, इसलिए आप वास्तव में नहीं जानते कि आपके कोड के कौन से भाग डीआई फ्रेमवर्क के बाहर पुन: उपयोग करने के लिए सुरक्षित हैं (उदाहरण के लिए, भीतर आपके यूनिट परीक्षण, या पूरी तरह से किसी अन्य परियोजना में)।
अद्यतन: मैं एक blog post जो अधिक विस्तार में Reader
बताते ऊपर लिखा था।
'val's * * प्रतिबिंब का उपयोग कर संशोधित किया जा सकता है, इसलिए यह है कि आपके निर्भरता इंजेक्शन पुस्तकालय – gerferra
क्या वैल की बात प्रतिबिंब द्वारा संशोधित किया गया है @gerferra" एक वैल इंजेक्षन "कर सकता है, अगर हम वर है संभव है? –
क्यों 'ग्राहक' को तर्क के साथ कक्षा नहीं बनाते हैं, इसलिए कॉन्फ़िगरेशन को 'क्लाइंट' के उदाहरणों में पारित किया जा सकता है? –