2009-05-05 7 views
24

मैं जो कुछ डीडीडी एंटरप्राइज़ ऐप्स पर काम करता हूं, उसमें एक चीज जो मैं काम करता हूं, इंटरफेस का उपयोग डोमेन इकाइयों के समान है, गुणों और कार्यों के एक-से-एक मैपिंग के साथ। दरअसल, एक डोमेन ऑब्जेक्ट का हमेशा एक-से-एक इंटरफ़ेस के माध्यम से उपयोग किया जाता है, और सभी डोमेन इकाइयों के पास इस शैली में एक-से-एक इंटरफ़ेस होता है।डोमेन इकाइयों के साथ एक-से-एक इंटरफेस का उपयोग करना एक अच्छा या बुरा अभ्यास है? क्यूं कर?

उदाहरण के लिए:

डोमेन वस्तु खाता:

public class Account : IAccount 
{ 
    public string Name {get;set;} 
    //...some more fields that are also in IAccount 
    public decimal Balance {get;set;} 
} 

और यह मिलान है इंटरफ़ेस

public interface IAccount 
{ 
    string Name {get;set;} 
    //... all the fields in Account 
    decimal Balance {get;set;} 
} 

लेकिन हाल ही में मैं तेजी से आश्वस्त हैं कि यह है बन गया है, वास्तव में, एक विरोधी -pattern।
मैंने इसे कुछ स्रोतों द्वारा ओपन सोर्स समुदाय में चलाया, और वे कहते हैं कि यह डिज़ाइन की गलतियों या त्रुटियों पर आधारित है, कहीं भी डिजाइन की श्रृंखला है।

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

सबसे पहले दावा किया गया था कि ये इंटरफेस 'decoupling' प्रदान करते हैं, लेकिन मैं इसका सामना करता हूं क्योंकि इंटरफेस डोमेन डोमेन के साथ एक-से-एक संबंध है कि वे वास्तव में कोई decoupling प्रदान नहीं करते हैं, इंटरफ़ेस में परिवर्तन का मतलब है डोमेन इकाई में बदलाव और इसके विपरीत।

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

तो मैं उत्सुक हूँ:

क्यों आप अपने डोमेन संस्थाओं के लिए एक-से-एक इंटरफेस के लिए होता है?

क्यों नहीं?

यह एक अच्छा या बुरा अभ्यास क्यों है?

पढ़ने के लिए धन्यवाद!

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

+0

AFAIK राइनो मोक्स कंक्रीट क्लास विधियों का नकल नहीं कर सकते हैं जब तक वे ओवरराइड करने योग्य नहीं होते। इस प्रकार आपको सभी डोमेन ऑब्जेक्ट विधियों को आभासी बनाना होगा। अच्छा नही। –

+0

संबंधित: http://stackoverflow.com/questions/2659366/java-interfaces-methodology-should-every-class-implement-an-interface – jaco0646

उत्तर

8

यह एक बुरा व्यवहार के रूप में वर्णित है, लेकिन ...

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

अपने उदाहरण का उपयोग करने के लिए, आपके द्वारा वर्णित IAccount इंटरफ़ेस खाता ऑब्जेक्ट पर गेटर्स और सेटर्स का खुलासा करता है; यह थोड़ा अजीब और असंभव लगता है कि खाते का उपयोग करने वाली हर चीज़ को खाते पर शेष राशि निर्धारित करने की आवश्यकता होगी, और उस अंतर्निहित अनुमति को उस इंटरफ़ेस के स्तर पर निर्दिष्ट किया गया है।क्या आपके सिस्टम में कोई जगह नहीं है जहां आप केवल जांच करना चाहते हैं लेकिन खाता शेष सेट नहीं करना चाहते हैं?

+0

हां, ऐसे क्षेत्र हैं जहां पूरे इंटरफ़ेस का उपयोग नहीं किया जाता है। वास्तव में यह अधिक मामला है कि इंटरफ़ेस का एक हिस्सा उपयोग नहीं किया जाता है। –

+1

हाँ, ऐप्स डोमेन-संचालित डिज़ाइन नहीं हैं; यह शुद्ध डेटा संचालित डिजाइन है। और ऐसा लगता है कि यह बहुत खराब डिजाइन है, इसके लिए। –

+0

मुझे दुख की बात है ... –

7

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

लेकिन क्या होगा अगर आप था, उदाहरण के लिए:

public class Account : IAccount { ... }  // Usual account, persistent 
public class MockAccount : IAccount { ... } // Test mock object 
public class TransAccount : IAccount { ... } // Account, not persistent 
public class SimAccount : IAccount { ... } // Account in a performance sim 

और इतने पर?

डोमेन ऑब्जेक्ट्स को इंटरफेस के रूप में परिभाषित करके, आप अपनी डोमेन परिभाषा को परेशान किए बिना कार्यान्वयन को प्रतिस्थापित कर सकते हैं।

+0

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

+0

+1 यह मूर्खतापूर्ण प्रतीत होता है जब तक आप एक मोनोलिथिक एप्लिकेशन पर रखरखाव में दो साल नहीं होते हैं और आपको निर्भरताओं की परतों को बाधित किए बिना नए बदलावों का समर्थन करने के लिए एक परिवर्तन को लागू करने की आवश्यकता होती है। इसके अलावा, टीडीडी एक ब्रेनर है। –

+0

यदि आप पहले से ही जवाब जानते हैं, तो आप सवाल क्यों पूछ रहे हैं? –

5

सामान्य रूप से, यदि मेरी कक्षाएं रणनीति या विज़िटर जैसे डिज़ाइन पैटर्न का हिस्सा नहीं बनती हैं, तो मैं इंटरफेस नहीं जोड़ता हूं।

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

interface SomeStrategy { 
    void doSomething(StrategyData data); 
} 

interface StrategyData { 
    String getProperty1(); 

    String getProperty2(); 
} 

इससे मुझे डोमेन कक्षाएं उन इंटरफेस को लागू करने या एडाप्टर पैटर्न का उपयोग करने की अनुमति देती हैं। मुझे लगता है कि यह एक बहुत साफ दृष्टिकोण है जो इसके लिए इंटरफेस बना रहा है।

डिज़ाइन हमेशा अनिश्चितता को कम करना चाहिए। इसके लिए इंटरफेस बनाना अनिश्चितता को कम नहीं करता है, वास्तव में यह शायद भ्रम को बढ़ाता है क्योंकि इससे कोई अर्थ नहीं होता है।

+0

अच्छा जवाब, thx –

3

एक-से-एक संस्थाओं पर इंटरफेस एक विरोधी पैटर्न

जेम्स ग्रेगरी बेहतर डाल मुझे here से कर रहे हैं।

+0

उत्कृष्ट उत्तर, लिंक के लिए धन्यवाद! –

+0

बेशक एनीमिक डोमेन असली मुद्दा है। लेकिन जब आपके पास पहले से ही एक है। आप कम से कम डिप्लेंडर और कार्यान्वयन के बीच एक इन्सुलेटर बना सकते हैं ताकि आप कम सिरदर्द के साथ बदल सकें। – jeremyjjbrown

0

यह क्यों एक झुका हुआ है?

मुझे डोमेन ऑब्जेक्ट के लिए एक इंटरफेस मिल रहा है, क्योंकि चार्ली मार्टिन ने कहा, मुझे अपना कार्यान्वयन चुनने की अनुमति देता है।

एक मौलिक उदाहरण किसी ऑब्जेक्ट के लिए पहचानकर्ता (ऑब्जेक्ट.आईडी) है, यह उस वस्तु के आधार पर अलग होगा जहां आप उस ऑब्जेक्ट को स्टोर करते हैं और इसे बनाने की ज़िम्मेदारी बाद में डेटा के कार्यान्वयन में हो सकती है या नहीं। SQL सर्वर में आप एक ऑटोऑनंबर के लिए जा सकते हैं, लेकिन एज़ूर टेबल स्टोरेज में आप एक ग्रिड के लिए जा सकते हैं, लेकिन आप अपने ऐप के व्यवसाय तर्क को बदलना नहीं चाहते हैं क्योंकि आप अपना डेटा कहां बदलते हैं।

मैं अपना डोमेन ऑब्जेक्ट जारी रखना चुन सकता हूं या यहां तक ​​कि प्रस्तुति परत में इसका उपयोग नहीं कर सकता - यह मेरे ऐप के दायरे पर निर्भर करता है जो सबसे अच्छा है। लेकिन एक आम परत में सामान्य डोमेन इंटरफेस का एक सेट जोड़ने से मैं उनके खिलाफ सेवाएं लिख सकता हूं और उन्हें दोबारा उपयोग कर सकता हूं।

अगर हम आईएड्रेस नहीं मिला तो हम एक पते के बारे में एक ही तर्क पर जायेंगे, नए प्रोग्रामर क्रेडिट कार्ड के लिए सामान लिख रहे होंगे यदि यह आईसी क्रेडिट कार्ड के लिए नहीं था।

एंटी-पैटर्न लेबल भाषा का खराब उपयोग है, यह जटिल और विविध कार्यों के समाधान के मूल्य का वर्णन करने के लिए एक अधिक सरलीकरण है।

अधिकांश पैटर्न के लिए एक जगह भी है, यहां तक ​​कि बदनाम सिंगलटन भी है, जिसका अर्थ है कि यह "विरोधी पैटर्न" नहीं है, कम से कम जहां तक ​​यह शब्द सुझाता है।

+0

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

+0

मैं हर बार एक स्ट्रिंग का उपयोग करता हूं, यदि आप जेनेरिक का उपयोग करते हैं तो रास्ता बहुत जटिल हो जाता है, आपको अपनी गुजरने वाले मॉडल में जेनेरिक के बारे में अपनी सेवाएं बताना होगा, और यदि इसमें एक उप संपत्ति है जो एक सामान्य इकाई है और सेवा सामान्य है - तुम मेरा अलग हो जाओ –

1

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