2011-09-20 12 views
5

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

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

public class MyClass 
{ 
    readonly ILogger _logger; 
    public MyClass(ILogger logger) 
    { 
     _logger = logger; 
    } 

    public int Divide(int x, int y) 
    { 
     if(y == 0) 
     { 
      _logger.Warn("y was 0"); 
      return 0; 
     } 
     return x/y; 
    } 
} 

एफ # में मैं मॉड्यूल एक बहुत अधिक उपयोग कर रहा हूँ, इसलिए यदि मुझे लगता है मैं सिर्फ इतना है कि खोलने के लिए और वहां से एक लॉग समारोह इस्तेमाल कर सकते हैं एक मॉड्यूल कहा जाता लॉगिंग था ऊपर

module Stuff 

let divde x y = 
    match y with 
    | 0 -> 0 
    | _ -> x/y 

बन जाएगा अब वाई होने के मामले में 0, लेकिन मैं यूनिट परीक्षण के लिए इसे कैसे इंजेक्ट करूँगा?

मैं प्रत्येक फ़ंक्शन को लॉग फ़ंक्शन (स्ट्रिंग -> इकाई) ले सकता हूं और फिर उन्हें वायरस करने के लिए आंशिक एप्लिकेशन का उपयोग कर सकता हूं लेकिन यह एक बहुत ही काम जैसा लगता है, जैसे कि एक नया फ़ंक्शन जो अंदर वास्तविक कॉल को लपेटता है एक लॉगिंग कॉल। क्या कोई विशेष पैटर्न या एफ # का थोड़ा सा है जो मुझे याद आ रहा है कि यह कर सकता है? (मैंने kprintf फ़ंक्शन देखा है लेकिन मुझे अभी भी पता नहीं है कि आप विभिन्न परीक्षण परिदृश्यों के लिए फ़ंक्शन निर्दिष्ट करते हैं, जबकि पूरे एप्लिकेशन के लिए ठोस कार्यान्वयन का उपयोग करते हुए)

इसी तरह आप एक संग्रह को कैसे रोकेंगे वह डेटा लाया? क्या आपको कुछ कक्षाओं को तत्काल स्थापित करने और सीआरयूडी कार्यों को सेट करने की आवश्यकता है, या आपके द्वारा खोले जाने वाले मॉड्यूल (#define से अलग) इंजेक्ट करने का कोई तरीका है

+0

http के लिए एक ही तकनीक सी # से कि आप जानते हैं कि उपयोग करने के लिए अनुमति चाहिए समान है /stackoverflow.com/questions/2003487/architectural-thinking-in- कार्यात्मक-भाषाएं http://stackoverflow.com/questions/192090/how-do-you-design-a- कार्यात्मक- प्रोग्राम –

उत्तर

2

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

एक विकल्प विभिन्न मॉड्यूल को शामिल करने के लिए प्रीप्रोसेसर निर्देशों का उपयोग कर रहा है।

#if TESTING 
open LogA 
#else 
open LogB 
#endif 

DI एक कार्यात्मक भाषा में एक गरीब फिट नहीं है। यह इंगित करने लायक है, एफ # इंटरफेस को परिभाषित और पूरा करने से भी आसान है, कहें, सी #।

+0

हम्म, तो कल्पना करें कि F # कक्षाओं में केवल रिकॉर्ड और डीयू नहीं थे, तो लॉगिंग को मॉड्यूल में जाना होगा क्योंकि आप आम तौर पर परिणाम के बजाय एक ऑपरेशन (कम से कम डीबग में) लॉग करना चाहते हैं एक ऑपरेशन का। इसका मतलब यह होगा कि डीआई खिड़की से बाहर है इसलिए आंशिक आवेदन बाकी है। क्या आप किसी भी मौके पर कार्यात्मक वास्तुकला के बारे में किसी भी पढ़ने की सिफारिश कर सकते हैं? जैसा कि यह बहुत लंबा रहा है, मुझे यकीन है कि इस तरह की चीजें पहले ही हल हो चुकी हैं लेकिन मैंने देखा है कि सभी किताबें "बड़े" – Dylan

+0

की बजाय "छोटे" पर ध्यान केंद्रित करती हैं, मेरी इच्छा है कि मैंने किया। मुझे भी इस शुरुआत के साथ संघर्ष करना याद है। मुझे उम्मीद है कि "बड़े" आर्किटेक्चर को एफ # में मूल रूप से अलग होना चाहिए। कुछ कार्यात्मक भाषाएं मॉड्यूल को पैरामीटरकृत करने की अनुमति देती हैं। दुर्भाग्य से, एफ # नहीं करता है। ओओ अभी भी "बड़े में" एक अच्छा दृष्टिकोण है। मुझे पता है कि सवाल SO पर कुछ बार देखा गया है। एक त्वरित खोज चालू: http://stackoverflow.com/questions/2003487/architectural-thinking-in- कार्यात्मक-भाषाएं। अन्य हो सकते हैं। – Daniel

+0

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

3

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

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

लॉगिंग के लिए वर्कफ़्लो (उर्फ मोनैड) को परिभाषित करना एक और (अधिक "शुद्ध") विकल्प होगा। यह केवल एक अच्छा विकल्प है यदि आप अपना सभी कोड एफ # में लिखते हैं। इस उदाहरण पर मेरी पुस्तक के अध्याय 12 में चर्चा की गई है, जो available as a free sample है।फिर आप इस तरह कुछ लिख सकते हैं:

let write(s) = log { 
    do! logMessage("writing: " + s) 
    Console.Write(s) } 

let read() = log { 
    do! logMessage("reading") 
    return Console.ReadLine() } 

let testIt() = log { 
    do! logMessage("starting") 
    do! write("Enter name: ") 
    let! name = read() 
    return "Hello " + name + "!" } 

इस दृष्टिकोण के बारे में अच्छी बात यह है कि यह एक अच्छी कार्यात्मक तकनीक है। परीक्षण कोड आसान होना चाहिए, क्योंकि एक फ़ंक्शन जो Log<'TResult> देता है, वह आपको एक मूल्य के साथ-साथ इसके दुष्प्रभावों का रिकॉर्ड भी देता है, ताकि आप परिणामों की तुलना कर सकें! हालांकि, यह एक ओवरकिल हो सकता है, क्योंकि आपको log { .. } ब्लॉक में लॉगिंग का उपयोग करने वाले प्रत्येक गणना को लपेटना होगा। /:

+0

धन्यवाद टॉमस, मैं अभी भी झुका हुआ हूं कि उत्परिवर्तन बुराई है। मेरे सी # कोड में मैं हमेशा निर्भरता को दृढ़ता से बना देता हूं। अगर मैं कोड में एक परिवर्तनीय लॉगर बनाता हूं तो मुझे लगता है कि इसे आकस्मिक पुन: असाइनमेंट से बचाने के लिए कोई आसान तरीका नहीं है। मुझे लगता है कि जैसा कि मैंने एक और टिप्पणी में उल्लेख किया है, हालांकि आवेदन के ऊपरी स्तर (व्युत्पन्न कार्यक्षमता) वैसे भी कम मॉड्यूल तक नहीं पहुंच पाएंगे। – Dylan

+0

@Dylan - हां, मॉड्यूल की घोषणा ऑर्डर संवेदनशील है, इसलिए आपके लॉगिंग मॉड्यूल को पहले जाना होगा। यह सच है कि सामान्य रूप से उत्परिवर्तन बुराई (एफ # में) है। हालांकि, अगर आपको लॉगर को फिर से गधे लगाने की आवश्यकता नहीं है, तो यह केवल सबसे आसान विकल्प है। –

0

यहाँ एफ # में अपनी सी # कोड के एक कार्यान्वयन जो करने के लिए प्रारंभिक सी #

module stuff 

type MyClass(logger:#Ilogger) = 
    member x.Divide a b = 
     if b=0 then 
      logger.Warn("y was 0") 
      0 
     else 
      x/y 

यह आप अपने प्रवेश

+0

धन्यवाद, लेकिन मैं इस प्रकार के दृष्टिकोण के लिए सी # का उपयोग करना चाहता हूं। मैंने वास्तव में इसे स्पष्ट नहीं किया था, लेकिन कक्षाओं के बिना रिकॉर्ड और फ़ंक्शन परिभाषाओं का उपयोग करके आप यह दृष्टिकोण कैसे करेंगे – Dylan

+0

एक नाबालिग नहीं - आपको इस मामले में '# ILogger' प्रकार की आवश्यकता नहीं है, क्योंकि F # विधि या कन्स्ट्रक्टर को कॉल करते समय स्वचालित रूप से कास्ट डालें। हैश-प्रकार का उपयोग करना थोड़ा अजीब लगता है - मुझे लगता है कि यह पूरी कक्षा जेनेरिक (लॉगर प्रकार पर पैरामीटरकृत) भी बनाता है, जिसकी आवश्यकता नहीं है। –

+0

@ टोमास - यह तब होता है जब मैं अपने कोड को जांचने के लिए कंपाइलर का उपयोग करने के लिए परेशान नहीं करता –