अद्यतन विधि में रिटर्न प्रकार जोड़ने से "एकल जिम्मेदारी सिद्धांत" का उल्लंघन होता है?


37

मेरे पास एक तरीका है जो डेटाबेस में कर्मचारियों के डेटा को अपडेट करता है। Employeeइसलिए "अद्यतन करने" वस्तु साधन वास्तव में एक नई वस्तु का दृष्टांत को वर्ग, अपरिवर्तनीय है।

मैं अद्यतन डेटा Updateके Employeeसाथ एक नया उदाहरण वापस करने के लिए विधि चाहता हूं , लेकिन अब से मैं कह सकता हूं कि विधि की जिम्मेदारी कर्मचारी डेटा को अपडेट करना है, और डेटाबेस से एक नई Employeeवस्तु प्राप्त करना है , क्या यह एकल जिम्मेदारी सिद्धांत का उल्लंघन करता है ?

DB रिकॉर्ड स्वयं अपडेट किया गया है। फिर, इस रिकॉर्ड का प्रतिनिधित्व करने के लिए एक नई वस्तु को त्वरित किया जाता है।


5
थोड़ा छद्म कोड यहाँ एक लंबा रास्ता तय कर सकता है: क्या वास्तव में एक नया डीबी रिकॉर्ड बनाया गया है, या डीबी रिकॉर्ड ही अपडेट किया गया है, लेकिन "क्लाइंट" कोड में एक नई वस्तु बनाई गई है क्योंकि वर्ग को अपरिवर्तनीय रूप में बनाया गया है?
मार्टिन बा

इसके अलावा मार्टिन ब्रा ने क्या पूछा, जब आप डेटाबेस को अपडेट कर रहे हैं तो आप एक एम्प्लोयी का उदाहरण क्यों दे रहे हैं? कर्मचारी उदाहरण के मान अपडेट पद्धति में नहीं बदले हैं, इसलिए इसे वापस क्यों करें (कॉल करने वालों के पास पहले से ही पहुंच ...)। या अद्यतन विधि भी डेटाबेस से (संभावित रूप से भिन्न) मानों को पुनः प्राप्त करती है?
थोरसल

1
@ डेटा: यदि आपकी डेटा इकाइयाँ अपरिवर्तनीय हैं, तो अपडेट किए गए डेटा के साथ एक इंस्टेंस लौटना बहुत ज्यादा SOP है, अन्यथा आपको संशोधित डेटा का इंस्टेंटेशन खुद करना होगा।
मिक्लोक्

21
Compare-and-swapऔर test-and-setबहु-थ्रेडेड प्रोग्रामिंग के सिद्धांत में मौलिक संचालन हैं। वे दोनों एक वापसी प्रकार के साथ अपडेट तरीके हैं, और अन्यथा काम नहीं कर सकते। क्या यह कमांड-क्वेरी पृथक्करण या एकल जिम्मेदारी सिद्धांत जैसी अवधारणाओं को तोड़ता है? हाँ, और वह पूरा बिंदु है । एसआरपी एक सार्वभौमिक अच्छी चीज नहीं है, और वास्तव में सक्रिय रूप से हानिकारक हो सकता है।
एमएसलटर्स

3
@ मालिक: बिल्कुल। कमांड / क्वेरी पृथक्करण का कहना है कि ऐसे प्रश्नों को जारी करना संभव है, जिन्हें आदर्श के रूप में पहचाना जा सकता है, और आदेशों को बिना किसी उत्तर के प्रतीक्षा करने के लिए जारी किया जा सकता है, लेकिन परमाणु पठन-संशोधित-लेखन को संचालन की तीसरी श्रेणी के रूप में मान्यता दी जानी चाहिए।
Supercat

जवाबों:


16

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

एकल-जिम्मेदारी नियम का उद्देश्य प्रत्येक कार्य को एक आत्म निहित, सुसंगत चीज बनाकर समझने और बनाए रखने के लिए कार्यक्रमों को आसान बनाना है।

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

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

आपके मामले में, डेटाबेस को अपडेट करें और लिखे गए रिकॉर्ड की एक छवि लौटाएं, ऐसा लगता है कि दो चीजें अच्छी तरह से तार्किक और अनिवार्य रूप से एक साथ चल सकती हैं। मुझे आपके आवेदन का विवरण नहीं पता है इसलिए मैं निश्चित रूप से नहीं कह सकता कि यह एक अच्छा विचार है या नहीं, लेकिन यह प्रशंसनीय लगता है।

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

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

लेकिन मुझे लगता है कि परिदृश्य 1 अधिक संभावना है, इसलिए मैं कहूंगा, शायद कोई समस्या नहीं है।


सभी उत्तर के लिए धन्यवाद, लेकिन इस एक ने मुझे वास्तव में सबसे अधिक मदद की।
सिपो

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

public function sendDataInClientFormat() { formatDataForClient(); sendDataToClient(); } private function formatDataForClient() {...} private function sendDataToClient() {...}
सीजे डेनिस

@CJDennis ज़रूर। और वास्तव में यह है कि मैंने यह कैसे किया: स्वरूपण करने के लिए एक फ़ंक्शन, वास्तविक भेजने के लिए एक फ़ंक्शन, और दो अन्य फ़ंक्शन थे जो मुझे यहां नहीं मिलेंगे। फिर उन सभी को उचित क्रम में बुलाने के लिए एक शीर्ष-स्तरीय कार्य। आप कह सकते हैं "प्रारूप और भेजें" एक तार्किक ऑपरेशन है और इस प्रकार एक फ़ंक्शन में ठीक से जोड़ा जा सकता है। यदि आप जोर देते हैं कि यह दो है, ठीक है, तो अभी भी तर्कसंगत बात करने के लिए एक शीर्ष-स्तरीय फ़ंक्शन है जो यह सब करता है।
जय

67

SRP की अवधारणा मॉड्यूल को 2 अलग-अलग कामों को रोकने के लिए है जब उन्हें व्यक्तिगत रूप से करना बेहतर रखरखाव और समय में कम स्पेगेटी के लिए बनाता है। जैसा कि एसआरपी कहता है "परिवर्तन का एक कारण"।

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

एसआरपी वास्तव में एक कॉल पर सभी ऑपरेशनों को कम करने की कोशिश करने के बारे में नहीं है, लेकिन यह कम करने के लिए कि आप किस पर काम कर रहे हैं और आप उस पर कैसे काम कर रहे हैं। अतः अद्यतन वस्तु को लौटाने वाला एकल अद्यतन ठीक है।


7
वैकल्पिक रूप से, यह "एकल कॉल के लिए सभी ऑपरेशनों को कम करने की कोशिश करने के बारे में नहीं है", लेकिन सवाल में आइटम का उपयोग करते समय आपको कितने अलग-अलग मामलों के बारे में सोचना है।
jpmc26

46

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

स्पेक्ट्रम के दूसरे छोर पर वे विधियाँ हैं जिनसे किसी वस्तु की स्थिति के बारे में जानकारी मिलती है। ठेठ isActiveने इस जानकारी को अपनी एकल जिम्मेदारी के रूप में दिया है। शायद सभी सहमत हैं कि यह ठीक है।

अब, कुछ इस सिद्धांत को इतना आगे बढ़ाते हैं कि वे सफलता के झंडे को वापस लौटाने पर विचार करते हैं, जिसकी कार्रवाई के लिए एक अलग जिम्मेदारी होती है जिसकी सफलता बताई जा रही है। एक अत्यंत सख्त व्याख्या के तहत, यह सच है, लेकिन चूंकि विकल्प सफलता की स्थिति प्राप्त करने के लिए एक दूसरी विधि को कॉल करने के लिए होगा, जो कॉलर को जटिल करता है, कई प्रोग्रामर साइड इफेक्ट के साथ एक विधि से सफलता के कोड वापस करने के साथ पूरी तरह से ठीक हैं।

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


15
अगर आपको यह देखने के लिए दूसरी विधि को कॉल करना है कि क्या पहला सफल हुआ है, तो क्या आपको दूसरे के परिणाम प्राप्त करने के लिए तीसरी विधि नहीं बुलानी चाहिए? फिर अगर आप वास्तव में परिणाम चाहते हैं , तो ...

3
मैं जोड़ सकता हूं कि एसआरपी के अति उत्साही आवेदन से छोटी कक्षाओं का एक असंख्य होता है, जो अपने आप में एक बोझ है। कितना बड़ा बोझ अपने वातावरण, संकलक, आईडीई / सहायक उपकरण आदि पर निर्भर करता है
एरिक Alapää

8

क्या यह एकल जिम्मेदारी सिद्धांत का उल्लंघन करता है?

जरुरी नहीं। यदि कुछ भी हो, तो यह कमांड-क्वेरी अलगाव के प्रिंसिपल का उल्लंघन करता है ।

जिम्मेदारी है

कर्मचारी डेटा को अपडेट करें

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

फिर, यह सब डिग्री और व्यक्तिपरक निर्णय का विषय है।


तो कमांड-क्वेरी अलगाव के बारे में क्या?

ठीक है, वह सिद्धांत मौजूद है, लेकिन एक अद्यतन का परिणाम वापस करना वास्तव में बहुत आम है।

(1) जावा Set#add(E)तत्व जोड़ता है और सेट में अपना पिछला समावेश देता है।

if (visited.add(nodeToVisit)) {
    // perform operation once
}

यह CQS विकल्प की तुलना में अधिक कुशल है, जिसमें दो लुकअप करने पड़ सकते हैं।

if (!visited.contains(nodeToVisit)) {
    visited.add(nodeToVisit);
    // perform operation once
}

(2) तुलना-और-अदला-बदली , लाने और जोड़ने , और परीक्षण-और-सेट आम आदिम हैं जो समवर्ती प्रोग्रामिंग को मौजूद करने की अनुमति देते हैं। निम्न-स्तर सीपीयू निर्देशों से लेकर उच्च-स्तरीय समवर्ती संग्रह तक ये पैटर्न अक्सर दिखाई देते हैं।


2

एकल जिम्मेदारी एक वर्ग के बारे में है जिसे एक से अधिक कारणों से बदलने की आवश्यकता नहीं है।

एक उदाहरण के रूप में एक कर्मचारी के पास फोन नंबरों की एक सूची है। जब आप फोन नंबर परिवर्तन को संभालते हैं (आप देश कॉलिंग कोड जोड़ सकते हैं) जो कि कर्मचारी वर्ग को बिल्कुल भी नहीं बदलना चाहिए।

मुझे कर्मचारी वर्ग को यह जानने की आवश्यकता नहीं होगी कि यह डेटाबेस के लिए खुद को कैसे बचाता है, क्योंकि यह तब कर्मचारियों में बदलाव और डेटा को कैसे संग्रहीत किया जाता है, में परिवर्तन होगा।

इसी तरह कर्मचारी वर्ग में एक गणनात्मक पद्धति नहीं होनी चाहिए। एक वेतन संपत्ति ठीक है, लेकिन कर आदि की गणना कहीं और की जानी चाहिए।

लेकिन यह है कि अद्यतन विधि ने जो अभी अद्यतन किया है वह ठीक है।


2

WRT। विशिष्ट मामला:

Employee Update(Employee, name, password, etc) (वास्तव में एक बिल्डर का उपयोग करने के बाद से मेरे पास बहुत सारे पैरामीटर हैं)।

ऐसा लगता है कि Updateविधि Employeeमौजूदा कर्मचारी को पहचानने के लिए पहले पैरामीटर के रूप में मौजूदा कर्मचारी को लेती है और इस कर्मचारी को बदलने के लिए मापदंडों का एक सेट है।

मुझे लगता है कि यह क्लीनर किया जा सकता है। मैं दो मामले देखता हूं:

(ए) Employee में वास्तव में एक डेटाबेस / अद्वितीय आईडी होती है जिसके द्वारा इसे डेटाबेस में हमेशा पहचाना जा सकता है। (यही है, आपको डीबी में इसे खोजने के लिए पूरे रिकॉर्ड मानों की आवश्यकता नहीं है।

इस मामले में, मैं एक void Update(Employee obj)विधि पसंद करूंगा , जिसमें सिर्फ आईडी द्वारा मौजूदा रिकॉर्ड का पता लगाया जाए और फिर पास की गई वस्तु से फ़ील्ड को अपडेट किया जाए। या शायद एvoid Update(ID, EmployeeBuilder values)

इसका एक रूपांतर जो मुझे उपयोगी लगा, वह केवल एक void Put(Employee obj)विधि है जो आवेषण या अद्यतन करता है, जो इस बात पर निर्भर करता है कि क्या रिकॉर्ड (आईडी द्वारा) मौजूद है।

(बी) डीबी लुकअप के लिए पूर्ण मौजूदा रिकॉर्ड की आवश्यकता है, उस स्थिति में यह अभी भी अधिक समझ में आ सकता है void Update(Employee existing, Employee newData):।

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

अन्य उत्तर (परमाणु सेट-एंड-रिवाइव / तुलना-स्वैप, आदि) में उल्लिखित समवर्ती आवश्यकताओं को डीबी कोड मैंने अब तक काम किया है में कोई समस्या नहीं है। डीबी से बात करते समय, मुझे लगता है कि इसे लेन-देन के स्तर पर सामान्य रूप से नियंत्रित किया जाना चाहिए, न कि व्यक्तिगत विवरण स्तर पर। (यह कहने के लिए नहीं है कि ऐसा कोई डिज़ाइन नहीं हो सकता है जहाँ "परमाणु" Employee[existing data] Update(ID, Employee newData)का कोई अर्थ नहीं हो सकता है, लेकिन डीबी पहुँच के साथ ऐसा कुछ नहीं है जिसे मैं सामान्य रूप से देखता हूं।)


1

अब तक यहां हर कोई कक्षाओं के बारे में बात कर रहा है। लेकिन इसके बारे में एक इंटरफेस के नजरिए से सोचें।

यदि कोई इंटरफ़ेस विधि रिटर्न प्रकार की घोषणा करती है, और / या रिटर्न वैल्यू के बारे में एक निहित वादा करता है, तो हर कार्यान्वयन को अद्यतन ऑब्जेक्ट को वापस करने की आवश्यकता होती है।

तो आप पूछ सकते हैं:

  • क्या आप उन संभावित क्रियान्वयनों के बारे में सोच सकते हैं जो एक नई वस्तु को वापस करने के लिए परेशान नहीं करना चाहते हैं?
  • क्या आप उन घटकों के बारे में सोच सकते हैं जो इंटरफ़ेस पर निर्भर करते हैं (उदाहरण के लिए इंजेक्ट होने से), जिन्हें वापसी मूल्य के रूप में अद्यतन कर्मचारी की आवश्यकता नहीं है?

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

इन विचारों के आधार पर आप निर्णय ले सकते हैं।

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


0

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

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