डीटीओ के लिए रचना और विरासत का उपयोग करें


13

हमारे पास ASP.NET वेब API है जो हमारे सिंगल पेज एप्लीकेशन के लिए एक REST API प्रदान करता है। हम इस API के माध्यम से डेटा पास करने के लिए DTO / POCO का उपयोग करते हैं।

अब समस्या यह है, कि ये DTO समय के साथ बड़े होते जा रहे हैं, इसलिए अब हम DTO को फिर से तैयार करना चाहते हैं।

मैं "सर्वोत्तम प्रथाओं" की तलाश कर रहा हूं कि डीटीओ को कैसे डिज़ाइन किया जाए: वर्तमान में हमारे पास छोटे डीटीओ हैं जो केवल मूल्य-प्रकार के क्षेत्रों से मिलकर बने हैं, जैसे:

public class UserDto
{
    public int Id { get; set; }

    public string Name { get; set; }
}

अन्य DTO इस उपयोगकर्ता का उपयोग रचना द्वारा करते हैं, जैसे:

public class TaskDto
{
    public int Id { get; set; }

    public UserDto AssignedTo { get; set; }
}

इसके अलावा, कुछ विस्तारित डीटीओ हैं जो दूसरों से विरासत में मिले हैं, जैसे:

public class TaskDetailDto : TaskDto
{
    // some more fields
}

चूँकि कुछ DTOs का उपयोग कई एंडपॉइंट / विधियों (जैसे GET और PUT) के लिए किया गया है, उन्हें समय के साथ कुछ क्षेत्रों द्वारा बढ़ा दिया गया है। और विरासत और संरचना के कारण अन्य डीटीओ भी बड़े हो गए।

मेरा सवाल अब विरासत है और रचना अच्छी प्रथाओं नहीं है? लेकिन जब हम उनका पुन: उपयोग नहीं करते हैं, तो ऐसा लगता है कि एक ही कोड को कई बार लिखना। क्या कई समापन बिंदुओं / विधियों के लिए डीटीओ का उपयोग करना एक बुरा अभ्यास है, या अलग-अलग डीटीओ होने चाहिए, जो केवल कुछ बारीकियों में भिन्न हैं?


6
मैं आपको यह नहीं बता सकता कि आपको क्या करना चाहिए, लेकिन डीटीओ, विरासत और रचना के साथ काम करने का मेरा अनुभव जितनी जल्दी हो सकता है कि बाद में आप एक खराब कॉफी की तरह शिकार करते हैं। मैं फिर कभी डीटीओ का पुन: उपयोग नहीं करूंगा। कभी। इसके अलावा मैं समान डीटीओ को डीआरवाई उल्लंघन नहीं मानता। एक ही प्रतिनिधित्व को वापस करने वाले दो समापन बिंदु एक ही DTO का पुन: उपयोग कर सकते हैं। दो एंडपॉइंट्स जो समान प्रतिनिधित्व लौटाते हैं, वे एक ही डीटीओ नहीं लौटाते हैं इसलिए मैं प्रत्येक के लिए विशिष्ट डीटीओ बनाता हूं । यदि मुझे चुनने के लिए मजबूर किया गया था, तो रचना लंबे समय में कम समस्याग्रस्त है।
Laiv

@ इस सवाल का सही जवाब है, बस नहीं। यकीन नहीं होता कि आपने इसे टिप्पणी के रूप में क्यों रखा
TheCatWhisperer

2
@ लीव: आप इसके बजाय क्या उपयोग करते हैं? मेरे अनुभव में, इससे जूझने वाले लोग बस इसे उखाड़ फेंक रहे हैं। एक डीटीओ डेटा के लिए सिर्फ एक कंटेनर है, और यह सब है।
रॉबर्ट हार्वे

TheCatWhisperer क्योंकि मेरे तर्क मुख्य रूप से राय आधारित होंगे। मैं अभी भी अपनी परियोजनाओं में इस तरह की समस्याओं को दूर करने की कोशिश कर रहा हूं। @ रॉबर्टबेरवे सच, पता नहीं क्यों मैं चीजों को देखने से ज्यादा मुश्किल होता हूं क्योंकि वे वास्तव में हैं। मैं अभी भी समाधान पर काम कर रहा हूं। मुझे पूरा यकीन था कि एचएएल इन समस्याओं को हल करने के लिए मॉडल था, लेकिन आपके जवाब को पढ़कर मुझे एहसास हुआ कि मैं अपने डीटीओ को बहुत दानेदार भी करता हूं। इसलिए मैं पहले आपके दृष्टिकोण का अभ्यास करूंगा। परिवर्तनों को पूरी तरह से HATEOAS में स्थानांतरित करने की तुलना में कम नाटकीय होने जा रहा है।
लवि

एक अच्छी चर्चा के लिए इसे आज़माएं जो आपकी मदद कर सकती है: stackoverflow.com/questions/6297322/…
जॉनी

जवाबों:


10

सर्वोत्तम अभ्यास के रूप में, अपने डीटीओ को यथासंभव संक्षिप्त बनाने का प्रयास करें। केवल वही लौटें जो आपको वापस करने की आवश्यकता है। केवल वही उपयोग करें जो आपको उपयोग करने की आवश्यकता है। यदि इसका मतलब है कि कुछ अतिरिक्त डीटीओ हैं, तो यह हो।

आपके उदाहरण में, एक कार्य में एक उपयोगकर्ता शामिल है। एक को शायद वहां एक पूर्ण उपयोगकर्ता ऑब्जेक्ट की आवश्यकता नहीं होती है, शायद उस उपयोगकर्ता का नाम जिसे कार्य सौंपा गया है। हमें बाकी उपयोगकर्ता गुणों की आवश्यकता नहीं है।

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

इसके अलावा, कभी-कभी किसी को विरासत / रचना की आवश्यकता हो सकती है। मान लीजिए कि किसी के पास नौकरी है। एक कार्य में कई कार्य होते हैं। उस स्थिति में, नौकरी पाने से नौकरी के लिए कार्यों की सूची भी वापस आ सकती है। इसलिए, रचना के खिलाफ कोई नियम नहीं है। यह इस बात पर निर्भर करता है कि क्या मॉडल बनाया जा रहा है।


जैसा कि संभव है, इसका मतलब यह भी है कि मुझे डीटीओ को फिर से बनाना चाहिए, यदि वे कुछ विवरणों में भिन्न हैं - तो नहीं?
अधिकारी

1
@officer - सामान्य तौर पर, हाँ।
जॉन रेन्नोर

2

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

उदाहरण के लिए, मान लें कि आपके पास एक एंडपॉइंट है जो किसी चालान के लिए डेटा लौटाता है ताकि इसे स्क्रीन पर दिखाया जा सके या अंतिम उपयोगकर्ता को फ़ॉर्म में दिखाया जा सके। एक CRUD मॉडल में, आपको आवश्यक जानकारी को इकट्ठा करने के लिए अपने समापन बिंदु पर कई कॉल की आवश्यकता होगी: नाम, बिलिंग पता, शिपिंग पता, लाइन आइटम। एक व्यापारिक लेनदेन के संदर्भ में, एक एकल समापन बिंदु से एक एकल डीटीओ इस जानकारी को एक बार में वापस कर सकता है।


रॉबर्ट, क्या आप यहाँ एक सकल जड़ से मतलब है?
जॉनी

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

क्या सभी डेटा की आवश्यकता है?
रॉबर्ट हार्वे

1

डीटीओ के रूप में "लचीले" या सार के रूप में किसी चीज़ के लिए सर्वोत्तम अभ्यास स्थापित करना कठिन है। अनिवार्य रूप से, डीटीओ केवल डेटा ट्रांसफर के लिए ऑब्जेक्ट हैं, लेकिन गंतव्य या ट्रांसफर के कारण के आधार पर, आप अलग-अलग "वास्तविक प्रथाओं" को लागू करना चाह सकते हैं।

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

मूल रूप से, उन्हें महंगी रिमोट कॉल में उपयोग करने के लिए "डिज़ाइन" किया गया था, जहां आपको तर्क के विभिन्न हिस्सों से बहुत अधिक डेटा की आवश्यकता होगी; डीटीओ एक ही कॉल में डेटा ट्रांसफर करेंगे।

लेखक के अनुसार, डीटीओ का उद्देश्य स्थानीय वातावरण में इस्तेमाल नहीं किया जाना था, लेकिन कुछ लोगों ने उनके लिए उपयोग पाया। आमतौर पर वे GUI, API या अलग-अलग परतों के लिए अलग-अलग POCO से एक ही इकाई में जानकारी एकत्र करने के लिए उपयोग किए जाते हैं।

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

कुछ लोग रचना और विरासत के उपयोग को एक साथ करने की सलाह देते हैं, दोनों की ताकत का उपयोग करते हैं और अपनी कमजोरियों को कम करने की कोशिश करते हैं। निम्नलिखित नए DTO, या उस मामले के लिए किसी भी नए वर्ग / वस्तु को चुनते या बनाते समय मेरी मानसिक प्रक्रिया का हिस्सा है:

  • मैं एक ही परत या एक ही संदर्भ के अंदर डीटीओ के साथ विरासत का उपयोग करता हूं। एक DTO को कभी भी POCO से विरासत में नहीं मिलेगा, एक BLL DTO को DAL DTO से विरासत में कभी नहीं मिलेगा, आदि।
  • अगर मैं खुद को डीटीओ से एक क्षेत्र को छिपाने की कोशिश कर रहा हूं, तो मैं रिफ्लेक्टर करूंगा और शायद इसके बजाय रचना का उपयोग करूंगा।
  • यदि एक आधार डीटीओ से बहुत कम अलग-अलग क्षेत्र हैं जो मुझे चाहिए, तो मैं उन्हें एक सार्वभौमिक डीटीओ में डालूंगा। यूनिवर्सल डीटीओ का उपयोग केवल आंतरिक रूप से किया जाता है।
  • एक आधार POCO / DTO लगभग किसी भी तर्क के लिए उपयोग नहीं किया जाएगा, इस तरह से आधार केवल अपने बच्चों की जरूरतों का जवाब देता है। यदि मुझे कभी आधार का उपयोग करने की आवश्यकता होती है, तो मैं किसी भी नए क्षेत्र को जोड़ने से बचता हूं जो उसके बच्चे कभी उपयोग नहीं करेंगे।

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

public void DoSomething(BaseDTO base) {
    //Some code 
}

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

आपकी टिप्पणियों से मुझे लगता है कि आप नेस्टेड डीटीओ का उपयोग कर रहे हैं। यदि आपके नेस्टेड डीटीओ में केवल अन्य डीटीओ की सूची है, तो मुझे लगता है कि सबसे अच्छी बात यह है कि सूची को खोलना नहीं है।

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


मैं अपने उत्तर में 2 से अधिक लिंक नहीं जोड़ सका, यहाँ स्थानीय डीटीओ के बारे में कुछ और जानकारी दी गई है। मुझे पता है कि इसकी बहुत पुरानी जानकारी है, लेकिन मुझे लगता है कि इसमें से कुछ अभी भी प्रासंगिक हैं।
इवानग्राप्स

1

डीटीओ में रचना का उपयोग करना एक पूरी तरह से ठीक अभ्यास है।

ठोस प्रकार के डीटीओ के बीच विरासत का एक बुरा व्यवहार है।

एक बात के लिए, C # जैसी भाषा में, एक ऑटो-कार्यान्वित संपत्ति में बहुत कम रख-रखाव ओवरहेड होता है इसलिए उन्हें डुप्लिकेट करना (मैं वास्तव में घृणा दोहराता हूं) यह उतना हानिकारक नहीं है जितना कि यह अक्सर होता है।

डीटीओ के बीच ठोस विरासत का उपयोग नहीं करने का एक कारण यह है कि कुछ उपकरण ख़ुशी से उन्हें गलत प्रकारों के लिए मैप करेंगे।

उदाहरण के लिए, यदि आप डैपर की तरह डेटाबेस उपयोगिता का उपयोग करते हैं (मैं इसकी अनुशंसा नहीं करता हूं लेकिन यह लोकप्रिय है) जो कि class name -> table nameअनुमान लगाता है, तो आप पदानुक्रम में कहीं न कहीं एक ठोस आधार प्रकार के रूप में व्युत्पन्न प्रकार को बचाने में आसानी से समाप्त हो सकते हैं और इस तरह डेटा खो सकते हैं (इससे भी बदतर) ।

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

अब, एक चीज जिसके बारे में आप चिंतित हो सकते हैं , वह विभिन्न संबंधित डीटीओ के नाम और प्रकार के गुणों के बीच स्थिरता बनाए रख रही है ।

हालांकि, ठोस प्रकारों का उत्तराधिकार, इस तरह की स्थिरता सुनिश्चित करने में मदद करता है, उस तरह की स्थिरता बनाए रखने के लिए इंटरफेस (या C ++ में शुद्ध वर्चुअल बेस क्लास) का उपयोग करना बेहतर होता है।

निम्नलिखित डीटीओ पर विचार करें

interface IIdentity
{
    int Id { get; set; }
}

interface INamed
{
    string Name { get; set; }
}

public class UserDto: IIdentity, INamed
{
    public int Id { get; set; }

    public string Name { get; set; }

    // User specific properties
}

public class TaskDto: IIdentity
{
    public int Id { get; set; }

    // Task specific properties
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.