2012-07-09 7 views
17

मेरे सहयोगी और मेरे पास विवाद है। हम एक .NET अनुप्रयोग लिख रहे हैं जो बड़ी मात्रा में डेटा को संसाधित करता है। यह डेटा मानकों को प्राप्त करता है, कुछ मानदंडों के अनुसार उन्हें ब्लॉक में समूह समूह और उन ब्लॉक को संसाधित करता है।क्या मुझे अपने इंटरफेस पर IObservable <T> का खुलासा करना चाहिए?

के हम प्रकार Foo कुछ स्रोत पहुंचने के डेटा आइटम नहीं हैं (नेटवर्क से, उदाहरण के लिए) का कहना है कि एक के बाद एक करते हैं। हम सबसेट प्रकार Foo से संबंधित वस्तुओं की इकट्ठा प्रकार Bar में से प्रत्येक के इस तरह के सबसेट है और इस प्रक्रिया वस्तुओं से प्रकार Bar की एक वस्तु का निर्माण करना चाहते हैं।

हम में से एक ने निम्नलिखित डिज़ाइन का सुझाव दिया। इसका मुख्य विषय सीधे हमारे घटकों के इंटरफेस से IObservable<T> ऑब्जेक्ट्स को उजागर कर रहा है।

// ********* Interfaces ********** 
interface IFooSource 
{ 
    // this is the event-stream of objects of type Foo 
    IObservable<Foo> FooArrivals { get; } 
} 

interface IBarSource 
{ 
    // this is the event-stream of objects of type Bar 
    IObservable<Bar> BarArrivals { get; } 
} 

/********* Implementations ********* 
class FooSource : IFooSource 
{ 
    // Here we put logic that receives Foo objects from the network and publishes them to the FooArrivals event stream. 
} 

class FooSubsetsToBarConverter : IBarSource 
{ 
    IFooSource fooSource; 

    IObservable<Bar> BarArrivals 
    { 
     get 
     { 
      // Do some fancy Rx operators on fooSource.FooArrivals, like Buffer, Window, Join and others and return IObservable<Bar> 
     } 
    } 
} 

// this class will subscribe to the bar source and do processing 
class BarsProcessor 
{ 
    BarsProcessor(IBarSource barSource); 
    void Subscribe(); 
} 

// ******************* Main ************************ 
class Program 
{ 
    public static void Main(string[] args) 
    { 
     var fooSource = FooSourceFactory.Create(); 
     var barsProcessor = BarsProcessorFactory.Create(fooSource) // this will create FooSubsetToBarConverter and BarsProcessor 

     barsProcessor.Subscribe(); 
     fooSource.Run(); // this enters a loop of listening for Foo objects from the network and notifying about their arrival. 
    } 
} 
अन्य

एक और डिजाइन है कि इसकी मुख्य विषय हमारे अपने प्रकाशक/ग्राहक इंटरफेस का उपयोग करने और केवल आवश्यकता आरएक्स कार्यान्वयन के अंदर उपयोग कर रहा है का सुझाव दिया।

//********** interfaces ********* 

interface IPublisher<T> 
{ 
    void Subscribe(ISubscriber<T> subscriber); 
} 

interface ISubscriber<T> 
{ 
    Action<T> Callback { get; } 
} 


//********** implementations ********* 

class FooSource : IPublisher<Foo> 
{ 
    public void Subscribe(ISubscriber<Foo> subscriber) { /* ... */ } 

    // here we put logic that receives Foo objects from some source (the network?) publishes them to the registered subscribers 
} 

class FooSubsetsToBarConverter : ISubscriber<Foo>, IPublisher<Bar> 
{ 
    void Callback(Foo foo) 
    { 
     // here we put logic that aggregates Foo objects and publishes Bars when we have received a subset of Foos that match our criteria 
     // maybe we use Rx here internally. 
    } 

    public void Subscribe(ISubscriber<Bar> subscriber) { /* ... */ } 
} 

class BarsProcessor : ISubscriber<Bar> 
{ 
    void Callback(Bar bar) 
    { 
     // here we put code that processes Bar objects 
    } 
} 

//********** program ********* 
class Program 
{ 
    public static void Main(string[] args) 
    { 
     var fooSource = fooSourceFactory.Create(); 
     var barsProcessor = barsProcessorFactory.Create(fooSource) // this will create BarsProcessor and perform all the necessary subscriptions 

     fooSource.Run(); // this enters a loop of listening for Foo objects from the network and notifying about their arrival. 
    } 
} 

आपको कौन सा लगता है बेहतर है? IObservable<T> का खुलासा करना और हमारे घटकों को आरएक्स ऑपरेटरों से नई घटना धाराएं बनाना, या अपने स्वयं के प्रकाशक/ग्राहक इंटरफेस को परिभाषित करना और आवश्यकता होने पर आंतरिक रूप से आरएक्स का उपयोग करना?

  • पहले डिजाइन में हमारे इंटरफेस के उपभोक्ता उसका/उसकी उंगलियों पर आरएक्स की पूरी शक्ति है और किसी भी आरएक्स ऑपरेटरों प्रदर्शन कर सकते हैं:

    ये कुछ चीजें हैं डिजाइन के बारे में विचार करने के लिए कर रहे हैं। हम में से एक का दावा है कि यह एक फायदा है और अन्य दावे यह है कि यह एक कमी है।

  • दूसरे डिजाइन हमें हुड के नीचे किसी भी प्रकाशक/ग्राहक वास्तुकला का उपयोग करने की अनुमति देता है। पहला डिजाइन हमें आरएक्स से जोड़ता है।

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

+3

मुझे यह प्रश्न पसंद है जिस तरह से आप इसे पसंद करते हैं। "मेरे और मेरे सहयोगी के पास विवाद है।" +1। –

+3

सभी IObservable सामानों को * एक्सटेंशन विधियों * के रूप में क्यों न उजागर करें जो "गोंद कोड" का ख्याल रखते हैं।विकल्प की पेशकश करते समय, सभी ऑब्जेक्ट मॉडल को अपने ऑब्जेक्ट मॉडल से अलग रखता है। 'सार्वजनिक IOervervable AsObservable (यह IPublisher प्रकाशक) 'या कुछ समान – Will

+4

आपने संतुलित तरीके से प्रश्न पूछने का अच्छा काम किया है। –

उत्तर

14

IObservable<T> का खुलासा प्रदूषण किसी भी तरह से आरएक्स के साथ डिजाइन नहीं है। वास्तव में डिज़ाइन का निर्णय एक पुराना स्कूल .NET ईवेंट या अपने स्वयं के पब/उप तंत्र को घुमाने के बीच लंबित जैसा ही है। केवल अंतर यह है कि IObservable<T> नई अवधारणा है।

एक सबूत की आवश्यकता है? एफ # देखें जो एक .NET भाषा भी है लेकिन सी # से छोटा है। एफ # में प्रत्येक घटना IObservable<T> से निकली है। ईमानदारी से, मुझे पूरी तरह से उपयुक्त .NET पब/उप तंत्र को सारणित करने में कोई समझ नहीं है - यह IObservable<T> है - आपके घर के पब/उप अमूर्तता के साथ। बस IObservable<T> का पर्दाफाश करें।

अपने स्वयं के पब/उप अबास्ट्रक्शन को रोल करना मुझे लगता है कि जावा पैटर्न को .NET कोड में लागू करना है। अंतर यह है कि .NET में पर्यवेक्षक पैटर्न के लिए हमेशा महान ढांचा समर्थन रहा है और केवल खुद को रोल करने की आवश्यकता नहीं है।

0

एक अन्य विकल्प हो सकता है:

interface IObservableFooSource : IFooSource 
{ 
    IObservable<Foo> FooArrivals 
    { 
     get; 
    } 
} 

class FooSource : IObservableFooSource 
{ 
    // Implement the interface explicitly 
    IObservable<Foo> IObservableFooSource.FooArrivals 
    { 
     get 
     { 
     } 
    } 
} 

इस तरह केवल ग्राहकों है कि उम्मीद एक IObservableFooSource RX-विशिष्ट विधियों, उन है कि उम्मीद एक IFooSource या एक FooSource नहीं होगा देखेंगे।

8

सबसे पहले, यह ध्यान देने योग्य है कि IObservable<T>mscorlib.dll का हिस्सा है और System नाम स्थान, और इस तरह उजागर यह कुछ हद तक IComparable<T> या IDisposable उजागर के बराबर होगा है लायक है। जो आपके प्लेटफ़ॉर्म के रूप में .NET को चुनने के बराबर है, जो आपने पहले ही किया है।

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

आप मूल रूप से पूछ रहे हैं: क्या हम अपने सिस्टम में आरएक्स ऑपरेटरों के बिखरे हुए उपयोग को बढ़ावा देना चाहते हैं?।अब जाहिर है कि यह बहुत आमंत्रित नहीं है, क्योंकि आप संभवतः आरएक्स को तीसरी पार्टी लाइब्रेरी के रूप में देखते हैं।

किसी भी तरह से, उत्तर दो प्रस्तावित बेसल डिज़ाइनों में झूठ नहीं बोलता है, लेकिन उन डिज़ाइन के उपयोगकर्ताओं में। मैं आपके डिजाइन को अमूर्त स्तरों को तोड़ने की सलाह देता हूं, और यह सुनिश्चित कर रहा हूं कि आरएक्स ऑपरेटरों का उपयोग केवल एक स्तर पर स्कॉप्ड किया गया हो। जब मैं अमूर्त स्तर के बारे में बात करता हूं, तो मेरा मतलब है कि OSI Model के समान कुछ, केवल उसी एप्लिकेशन के कोड में।

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

अपने डिजाइन के दोनों की सादगी के बारे में, यह फैसला करने के बाद से Foo और Bar मुझे ज्यादा के बारे में उपयोग के मामलों, और इसलिए पठनीयता कारकों (जो, कर रहे हैं जिस तरह से, एक प्रयोग से अलग नहीं बताया वास्तव में मुश्किल है दूसरे मामले में)।

2

पहले डिजाइन में हमारे इंटरफेस के उपभोक्ता के पास उसकी उंगलियों पर आरएक्स की पूरी शक्ति होती है और कोई भी आरएक्स ऑपरेटर कर सकती है। हम में से एक का दावा है कि यह एक फायदा है और अन्य दावे यह है कि यह एक कमी है।

मैं आरएक्स की उपलब्धता के रूप में उपलब्धता के साथ सहमत हूं। कुछ कारण बताते हुए कि यह एक कमी क्यों है, यह निर्धारित करने में सहायता कर सकती है कि उन्हें कैसे संबोधित किया जाए। कुछ लाभ मैं देख रहा हूँ कर रहे हैं:

  • रतालू और क्रिस्टोफ के रूप में दोनों के खिलाफ ब्रश, IObservable/IObserver, .NET 4.0 के रूप में mscorlib में है, इसलिए यह (उम्मीद) एक मानक अवधारणा है कि हर किसी को तुरंत समझ जाएगा, घटनाओं की तरह बन जाएगा या IENumerable।
  • आरएक्स के ऑपरेटरों। एक बार जब आपको संभावित रूप से एकाधिक धाराओं को लिखना, फ़िल्टर करना या अन्यथा कुशलतापूर्वक उपयोग करना है, तो यह बहुत उपयोगी हो जाता है। आप शायद इस काम को अपने स्वयं के इंटरफेस के साथ किसी रूप में फिर से खोज लेंगे।
  • आरएक्स का अनुबंध। आरएक्स लाइब्रेरी एक अच्छी तरह से परिभाषित अनुबंध लागू करती है और जितना संभव हो उतना अनुबंध लागू कर सकती है। यहां तक ​​कि जब आपको अपने ऑपरेटरों को बनाने की आवश्यकता होती है, Observable.Create अनुबंध को लागू करने के लिए काम करेगा (यही कारण है कि IObservable को लागू करना सीधे आरएक्स टीम द्वारा अनुशंसित नहीं है)।
  • आरएक्स लाइब्रेरी के पास यह सुनिश्चित करने के अच्छे तरीके हैं कि जब आवश्यक हो तो आप सही धागे पर समाप्त हो जाएं।

मैंने ऑपरेटर का अपना हिस्सा लिखा है जहां लाइब्रेरी मेरे मामले को कवर नहीं करती है।

दूसरा डिजाइन हमें हुड के तहत किसी भी प्रकाशक/ग्राहक वास्तुकला का उपयोग करने की अनुमति देता है। पहला डिजाइन हमें आरएक्स से जोड़ता है।

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

आगे, आरएक्स लाइब्रेरी में ऑपरेटर हो सकते हैं जो "हुड के नीचे" भागों को सरल बना देंगे।

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

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

गोंद कोड सीधा है, लेकिन यदि आपको लगता है कि आप आरएक्स का उपयोग करेंगे, तो बस IObservable का पर्दाफाश करें और खुद को परेशानी बचाएं।

आगे विचार

मूल रूप से, अपने वैकल्पिक डिजाइन IObservable/IObserver से 3 मुख्य तरीकों अलग है।

  1. सदस्यता समाप्त करने का कोई तरीका नहीं है। प्रश्न की प्रतिलिपि बनाते समय यह सिर्फ एक निरीक्षण हो सकता है। यदि नहीं, तो क्या आप उस मार्ग पर जाने पर दृढ़ता से विचार करने के लिए कुछ है।
  2. डाउनस्ट्रीम प्रवाह करने के लिए त्रुटियों के लिए कोई परिभाषित पथ नहीं है (उदाहरण के लिए IObserver.OnError)।
  3. स्ट्रीम के समापन को इंगित करने का कोई तरीका नहीं है (उदाहरण के लिए IObserver.OnCompleted)। यह केवल तभी प्रासंगिक है जब आपका अंतर्निहित डेटा एक समाप्ति बिंदु है।

आपका वैकल्पिक डिज़ाइन इंटरफ़ेस पर एक विधि के रूप में कॉलबैक को एक क्रिया के रूप में भी लौटाता है, लेकिन मुझे नहीं लगता कि भेद महत्वपूर्ण है।

आरएक्स लाइब्रेरी एक कार्यात्मक दृष्टिकोण को प्रोत्साहित करती है। आपकी FooSubsetsToBarConverter कक्षा IObservable<Foo> पर एक्सटेंशन विधि के रूप में बेहतर होगी जो IObservable<Bar> लौटाती है। यह अव्यवस्था को थोड़ा कम कर देता है (एक समारोह के साथ एक वर्ग को क्यों बनाते हैं जब कोई फ़ंक्शन ठीक करेगा) और शेष आरएक्स लाइब्रेरी की श्रृंखला-शैली संरचना के साथ बेहतर फिट बैठता है। आप वैकल्पिक इंटरफेस के लिए एक ही दृष्टिकोण लागू कर सकते हैं, लेकिन ऑपरेटरों के बिना मदद करने के लिए, यह और अधिक कठिन हो सकता है।

+1

+1 अच्छा जवाब; अनुबंध महत्वपूर्ण है। कुछ गारंटी है कि अगर हम आरएक्स के अंदर रहते हैं तो हम मुफ्त में आते हैं, जिसमें अन्य LINQ monads जैसे INumerable/IQueryable/IQbservable के साथ साइड-इफेक्ट फ्री कंपोज़िशन की गारंटी शामिल है। घर लुढ़का पब/सब वे अपने डिजाइन में उन गारंटी नहीं दे सकते हैं जब तक कि वे मूल रूप से LINQ/Rx (monads) को पुन: पेश नहीं करते हैं। –

संबंधित मुद्दे