क्या किसी पैरामीटर को संशोधित करना फ़ंक्शन के लिए ठीक है


17

हमारे पास एक डेटा लेयर है जो Linq To SQL को लपेटता है। इस डेडलेयर में हमारे पास यह तरीका है (सरलीकृत)

int InsertReport(Report report)
{
    db.Reports.InsertOnSubmit(report);
    db.SubmitChanges();
    return report.ID; 
}

परिवर्तन सबमिट करने पर, रिपोर्ट आईडी उस डेटाबेस में मूल्य के साथ अपडेट की जाती है जिसे हम फिर से लौटाते हैं।

कॉलिंग की ओर से यह इस तरह दिखता है (सरलीकृत)

var report = new Report();
DataLayer.InsertReport(report);
// Do something with report.ID

कोड को देखते हुए, InsertReport फ़ंक्शन के अंदर एक प्रकार के साइड इफेक्ट के रूप में ID सेट किया गया है, और फिर हम रिटर्न वैल्यू को अनदेखा कर रहे हैं।

मेरा सवाल यह है कि क्या मुझे साइड इफेक्ट पर भरोसा करना चाहिए और इसके बजाय ऐसा कुछ करना चाहिए।

void InsertReport(Report report)
{
    db.Reports.InsertOnSubmit(report);
    db.SubmitChanges();
}

या हमें इसे रोकना चाहिए

int InsertReport(Report report)
{
    var newReport = report.Clone();
    db.Reports.InsertOnSubmit(newReport);
    db.SubmitChanges();
    return newReport.ID; 
}

यहां तक ​​कि

Report InsertReport(Report report)
{
    var newReport = report.Clone();
    db.Reports.InsertOnSubmit(newReport);
    db.SubmitChanges();
    return newReport; 
}

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


2
यह वही है जो एपीआई प्रलेखन के लिए है।

जवाबों:


16

हां, यह ठीक है, और काफी सामान्य है। यह गैर-स्पष्ट हो सकता है, जैसा कि आपने खोजा है।

सामान्य तौर पर, मेरे पास दृढ़ता-प्रकार के तरीके हैं जो ऑब्जेक्ट के अपडेट किए गए इंस्टेंस को वापस करते हैं। अर्थात्:

Report InsertReport(Report report)
{        
    db.Reports.InsertOnSubmit(report);
    db.SubmitChanges();
    return report; 
}

हां, आप उसी वस्तु को लौटा रहे हैं जब आप पास हुए थे, लेकिन यह एपीआई को साफ करता है। क्लोन की कोई आवश्यकता नहीं है - अगर ऐसा कुछ भी जो भ्रम का कारण होगा, जैसा कि आपके मूल कोड में है, तो कॉल करने वाला उस ऑब्जेक्ट का उपयोग करना जारी रखता है जिसमें वे पास हुए थे।

एक अन्य विकल्प डीटीओ का उपयोग करना है

Report InsertReport(ReportDTO dto)
{
    var newReport = Report.Create(dto);
    db.Reports.InsertOnSubmit(newReport);
    db.SubmitChanges();
    return newReport; 
}

इस तरह से एपीआई बहुत स्पष्ट है, और कॉलर गलती से पारित / संशोधित वस्तु का उपयोग करने की कोशिश नहीं कर सकता है। आपका कोड क्या कर रहा है, इसके आधार पर, यह थोड़ा दर्द हो सकता है।


यदि ईरा की जरूरत नहीं है तो मैं वस्तु वापस नहीं करूंगा। अतिरिक्त प्रसंस्करण और मेमोरी (ओवर) के उपयोग की तरह। मैं एक शून्य या अपवाद चला गया, अगर जरूरत नहीं है। और, मैं अपने डीटीओ नमूने को वोट दिया।
स्वतंत्र

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

4

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


6
+1 - DB में एक इकाई डालने के बाद आप इसे एक आईडी की उम्मीद करेंगे । यह अधिक आश्चर्य की बात होगी अगर इकाई इसके बिना वापस आ गई।
मैडवेवी

2

समस्या यह है कि प्रलेखन के बिना, यह बिल्कुल स्पष्ट नहीं है कि विधि क्या कर रही है और विशेष रूप से यह पूर्णांक क्यों लौटा रही है।

सबसे आसान उपाय यह होगा कि आप अपने तरीके के लिए एक अलग नाम का उपयोग करें। कुछ इस तरह:

int GenerateIdAndInsert(Report report)

फिर भी, यह पर्याप्त नहीं है: यदि C # की तरह, reportऑब्जेक्ट का उदाहरण संदर्भ द्वारा पारित किया जाता है, तो यह जानना मुश्किल होगा कि क्या मूल reportऑब्जेक्ट को संशोधित किया गया था, या यदि विधि ने इसे क्लोन किया और केवल क्लोन को संशोधित किया। यदि आप मूल वस्तु को संशोधित करना चुनते हैं, तो विधि का नाम देना बेहतर होगा:

void ChangeIdAndInsert(Report report)

एक अधिक जटिल (और शायद कम इष्टतम) समाधान कोड को भारी रूप से रिफ्लेक्टर करना है। व्हाट अबाउट:

using (var transaction = new TransactionScope())
{
    var id = this.Data.GenerateReportId(); // We need to find an available ID...
    this.Data.AddReportWithId(id, report); // ... and use this ID to insert a report.
    transaction.Complete();
}

2

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

मैं यह भी तर्क दूंगा कि शायद IDयह भी नहीं होना चाहिए Report। चूंकि इसमें इतने लंबे समय के लिए एक वैध आईडी नहीं है, इसलिए आपके पास डालने से पहले और बाद में अलग-अलग व्यवहार के साथ दो अलग-अलग ऑब्जेक्ट हैं। "पहले" ऑब्जेक्ट डाला जा सकता है, लेकिन इसे पुनर्प्राप्त, अद्यतन या हटाया नहीं जा सकता। "बाद" वस्तु सटीक विपरीत है। एक के पास एक आईडी है और दूसरे के पास नहीं है। उनके प्रदर्शन के तरीके भिन्न हो सकते हैं। वे जिन सूचियों में दिखाई देते हैं वे भिन्न हो सकते हैं। संबद्ध उपयोगकर्ता अनुमतियाँ भिन्न हो सकती हैं। शब्द के अंग्रेजी अर्थ में वे दोनों "रिपोर्ट" हैं, लेकिन वे बहुत अलग हैं।

दूसरी ओर, आपका कोड काफी सरल हो सकता है कि एक वस्तु पर्याप्त होगी, लेकिन यह विचार करने के लिए कुछ है कि क्या आपके कोड के साथ peppered है if (validId) {...} else {...}


0

नहीं यह ठीक नहीं है! यह केवल प्रक्रियात्मक भाषाओं में एक पैरामीटर को संशोधित करने के लिए एक प्रक्रिया के लिए उपयुक्त है, जहां कोई अन्य तरीका नहीं है; ओओपी भाषाओं में वस्तु पर बदलती पद्धति को इस मामले में रिपोर्ट पर (रिपोर्ट की तरह कुछ भी कहा जाता है। GenerateNewId ())।

इस मामले में आपका तरीका 2 चीजें करता है, इसलिए एसआरपी को तोड़ता है: यह डीबी में एक रिकॉर्ड सम्मिलित करता है और यह एक नई आईडी उत्पन्न करता है। कॉल करने वाला यह जानने में सक्षम नहीं है कि आपकी विधि एक नई आईडी भी बनाती है, क्योंकि इसे बस इन्सर्टकार्ड () कहा जाता है।


3
एरम ... क्या होगा अगर db.Reports.InsertOnSubmit(report)ऑब्जेक्ट पर परिवर्तन विधि को कॉल करें?
स्टीफन C

यह ठीक है ... इसे टाला जाना चाहिए, लेकिन इस मामले में LINQ to SQL पैरामीटर संशोधन कर रहा है, तो ऐसा नहीं है कि ओपी ऐसा नहीं कर सकता है कि बिना हूप जंपिंग क्लोन प्रभाव (जो SRP का अपना उल्लंघन है) के बिना।
तेलस्टिन

@StephenC मैं कह रहा था कि आपको रिपोर्ट ऑब्जेक्ट पर उस विधि को कॉल करना चाहिए; इस मामले में एक पैरामीटर के रूप में एक ही वस्तु को पारित करने का कोई अर्थ नहीं है।
m3th0dman

@Telastyn I सामान्य मामले में बोल रहा था; अच्छी प्रथाओं का 100% सम्मान नहीं किया जा सकता है। उनके विशेष मामले में कोई भी अनुमान लगा सकता है कि कोड की 5 लाइनों से सबसे अच्छा तरीका क्या है ...
m3th0dman
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.