एक वर्ग की वास्तविक जिम्मेदारी क्या है?


42

मैं सोचता रहता हूं कि क्या OOP में संज्ञा पर आधारित क्रियाओं का उपयोग करना वैध है।
मैं इस शानदार लेख के पार आया , हालांकि मैं अभी भी इस बात से असहमत हूं।

समस्या को थोड़ा और समझाने के लिए, लेख में कहा गया है कि उदाहरण के लिए, एक FileWriterवर्ग नहीं होना चाहिए , लेकिन चूंकि लेखन एक क्रिया है इसलिए इसे कक्षा का एक तरीका होना चाहिए File। आपको एहसास होगा कि यह अक्सर भाषा पर निर्भर है क्योंकि एक रूबी प्रोग्रामर संभवतः एक FileWriterवर्ग के उपयोग के खिलाफ होगा (रूबी File.openएक फ़ाइल का उपयोग करने के लिए विधि का उपयोग करता है), जबकि एक जावा प्रोग्रामर नहीं होगा।

मेरा व्यक्तिगत (और हाँ, बहुत विनम्र) दृष्टिकोण यह है कि ऐसा करने से एकल जिम्मेदारी सिद्धांत टूट जाएगा। जब मैंने PHP में प्रोग्राम किया (क्योंकि PHP जाहिर है OOP के लिए सबसे अच्छी भाषा है, ठीक है?), मैं अक्सर इस तरह की रूपरेखा का उपयोग करता हूं:

<?php

// This is just an example that I just made on the fly, may contain errors

class User extends Record {

    protected $name;

    public function __construct($name) {
        $this->name = $name;
    }

}

class UserDataHandler extends DataHandler /* knows the pdo object */ {

    public function find($id) {
         $query = $this->db->prepare('SELECT ' . $this->getFields . ' FROM users WHERE id = :id');
         $query->bindParam(':id', $id, PDO::PARAM_INT);
         $query->setFetchMode( PDO::FETCH_CLASS, 'user');
         $query->execute();
         return $query->fetch( PDO::FETCH_CLASS );
    }


}

?>

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

मैं इस सी # कोड (इस पोस्ट में इस्तेमाल की जाने वाली चौथी वस्तु भाषा) को दूसरे दिन ही ले आया:

byte[] bytes = Encoding.Default.GetBytes(myString);
myString = Encoding.UTF8.GetString(bytes);

और मुझे लगता है कि यह मेरे लिए बहुत मायने नहीं रखता है कि एक Encodingया Charsetवर्ग वास्तव में तार एन्कोड करता है । यह केवल एक प्रतिनिधित्व होना चाहिए कि वास्तव में एन्कोडिंग क्या है।

इस प्रकार, मुझे लगता है कि होगा:

  • Fileफाइलों को खोलना, पढ़ना या सहेजना कोई वर्गीय जिम्मेदारी नहीं है ।
  • Xmlस्वयं को क्रमबद्ध करना कोई वर्गीय जिम्मेदारी नहीं है।
  • Userडेटाबेस को क्वेरी करना कोई क्लास की जिम्मेदारी नहीं है ।
  • आदि।

हालाँकि, अगर हम इन विचारों को अलग करते हैं, Objectतो एक toStringवर्ग क्यों होगा ? यह एक कार या एक कुत्ते की जिम्मेदारी नहीं है कि वह खुद को एक स्ट्रिंग में बदल दे, अब यह है?

मैं समझता हूं कि व्यावहारिक दृष्टिकोण से, toStringसख्त एसओएलआईडी फॉर्म का पालन करने की सुंदरता के लिए विधि से छुटकारा पाना , जो इसे बेकार बनाकर कोड को अधिक बनाए रखता है, स्वीकार्य विकल्प नहीं है।

मैं यह भी समझता हूं कि इसके लिए एक सटीक उत्तर (जो एक गंभीर उत्तर की तुलना में अधिक निबंध होगा ) नहीं हो सकता है, या यह राय-आधारित हो सकता है। फिर भी मैं यह जानना चाहूंगा कि क्या मेरा दृष्टिकोण वास्तव में एकल-जिम्मेदारी सिद्धांत का अनुसरण करता है।

कक्षा की जिम्मेदारी क्या है?


वस्तुओं को रखने की सुविधा ज्यादातर होती है, और आमतौर पर उपयोग के लिए आमतौर पर डीबगिंग के दौरान आंतरिक स्थिति को देखने के लिए उपयोग किया जाता है
शाफ़्ट फ्रीक

3
@ratchetfreak मैं सहमत हूं, लेकिन यह दिखाने के लिए एक उदाहरण (लगभग एक मजाक) था कि मेरे द्वारा वर्णित तरीके से एकल जिम्मेदारी बहुत बार टूट जाती है।
पियरे अरलाउड

8
जबकि एकल-जिम्मेदारी सिद्धांत के अपने उत्साही समर्थक हैं, मेरी राय में यह सबसे अच्छा दिशानिर्देश है, और डिजाइन विकल्पों के भारी बहुमत के लिए बहुत ढीली है। एसआरपी के साथ समस्या यह है कि आप सैकड़ों अजीब तरह से नामित वर्गों के साथ समाप्त हो जाते हैं, यह वास्तव में यह मुश्किल करता है कि आपको क्या चाहिए (या यह पता लगाने के लिए कि आपको क्या पहले से मौजूद है) और बड़ी तस्वीर को समझ लेना चाहिए। मैं बहुत अच्छी तरह से नामित वर्गों को पसंद करता हूं जो मुझे तुरंत बताते हैं कि क्या उनके पास उम्मीद है कि भले ही उनकी कुछ जिम्मेदारियां हों। अगर भविष्य में चीजें बदलती हैं तो मैं कक्षा को विभाजित कर दूंगा।
डंक

जवाबों:


24

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

सबसे पहले, तथाकथित "सिंगल रिस्पॉन्सिबिलिटी प्रिंसिपल" एक अवधारणा है - अवधारणा सामंजस्य की - स्पष्ट रूप से घोषित । उस समय ()70 के आसपास) के साहित्य को पढ़ते हुए, लोग यह परिभाषित करने के लिए (और अभी भी) संघर्ष कर रहे हैं कि एक मॉड्यूल क्या है, और उन्हें कैसे एक तरह से निर्माण करना है जो अच्छे गुणों को संरक्षित करेगा। तो, वे कहेंगे "यहाँ संरचनाओं और प्रक्रियाओं का एक समूह है, मैं उनमें से एक मॉड्यूल बनाऊंगा", लेकिन बिना किसी मापदंड के इस मानदंड के साथ कि क्यों मनमानी चीजों के इस सेट को एक साथ पैक किया जाता है, संगठन को कम समझदारी हो सकती है - थोड़ा "सामंजस्य"। इसलिए, मानदंड पर विचार-विमर्श हुआ।

इसलिए, यहां ध्यान देने वाली पहली बात यह है कि, अब तक, बहस संगठन और संबंधित रखरखाव और समझ पर प्रभाव के आसपास है (कंप्यूटर के लिए थोड़ी सी बात के लिए अगर एक मॉड्यूल "समझ में आता है")।

फिर, किसी और (श्रीमती मार्टिन) ने एक वर्ग की इकाई के लिए एक ही सोच को लागू किया और एक मानदंड के रूप में उपयोग करने के लिए जब यह सोचना चाहिए कि क्या होना चाहिए या क्या नहीं होना चाहिए, इस मानदंड को एक सिद्धांत को बढ़ावा देने के लिए, जिस पर चर्चा की जा रही है। यहाँ। उन्होंने जो बिंदु बनाया वह यह था कि "एक वर्ग को बदलने का केवल एक कारण होना चाहिए"

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

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

हालाँकि, अगर हम इन विचारों को अलग करते हैं, तो ऑब्जेक्ट को एक स्ट्रिंग कक्षा क्यों होगी? यह एक कार या एक कुत्ते की जिम्मेदारी नहीं है कि वह खुद को एक स्ट्रिंग में बदल दे, अब यह है?

अब, मुझे यहाँ कुछ कहने के लिए विराम देना चाहिए toString: आमतौर पर उपेक्षित एक बुनियादी बात है जब कोई व्यक्ति मॉड्यूल से कक्षाओं तक विचार का परिवर्तन करता है और यह दर्शाता है कि कक्षा के लिए क्या तरीके होने चाहिए। और बात गतिशील प्रेषण (उर्फ, देर से बाध्यकारी, "बहुरूपता") है।

बिना "ओवरराइडिंग विधियों" वाली दुनिया में, "obj.toString ()" या "toString (obj)" के बीच चयन करना केवल वाक्यविन्यास वरीयता का मामला है। हालांकि, एक ऐसी दुनिया में जहां प्रोग्रामर किसी मौजूदा / ओवरराइड विधि के अलग कार्यान्वयन के साथ एक उपवर्ग जोड़कर एक प्रोग्राम के व्यवहार को बदल सकते हैं, यह विकल्प स्वाद का अधिक नहीं है: एक विधि बनाना भी इसे ओवरराइडिंग के लिए एक उम्मीदवार बना सकता है। और "मुक्त प्रक्रियाओं" (बहु-विधियों का समर्थन करने वाली भाषाएं इस द्वंद्वात्मकता से बाहर निकलने का एक रास्ता है) के लिए सच नहीं हो सकता है। नतीजतन, यह केवल संगठन पर ही चर्चा नहीं है, बल्कि शब्दार्थ पर भी है। अंत में, विधि किस वर्ग से बंधी है, यह भी एक प्रभावशाली निर्णय बन जाता है (और कई मामलों में, अब तक हमारे पास दिशा-निर्देशों की तुलना में बहुत कम है कि हम यह तय कर सकें कि चीजें कहां हैं?

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


31

[नोट: मैं यहाँ वस्तुओं के बारे में बात करने जा रहा हूँ। ऑब्जेक्ट्स ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग के बारे में है, आखिरकार, कक्षाएं नहीं।]

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

जैसा कि हम सभी जानते हैं, "क्रिया / संज्ञा" पद्धति जिसे अक्सर परिचयात्मक पाठ्यक्रमों में पढ़ाया जाता है, हास्यास्पद है, क्योंकि यह इस बात पर निर्भर करता है कि आप एक वाक्य कैसे बनाते हैं। आप एक सक्रिय या एक निष्क्रिय आवाज़ में, संज्ञा या क्रिया के रूप में लगभग कुछ भी व्यक्त कर सकते हैं। आपके डोमेन मॉडल पर निर्भर होना गलत है, यह एक सचेत डिजाइन का विकल्प होना चाहिए कि क्या कोई वस्तु या विधि है या नहीं, यह केवल एक आकस्मिक परिणाम है कि आप आवश्यकताओं को कैसे बनाते हैं।

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

यहाँ एक उदाहरण है जो परिचयात्मक OO पाठ्यक्रमों में बहुत लोकप्रिय है: एक बैंक खाता। जो आमतौर पर एक balanceक्षेत्र और एक transferविधि के साथ एक वस्तु के रूप में तैयार किया जाता है । दूसरे शब्दों में: खाता शेष डेटा है , और एक हस्तांतरण एक ऑपरेशन है । जो एक बैंक खाते को मॉडल करने का एक उचित तरीका है।

को छोड़कर, यह नहीं है कि वास्तविक विश्व बैंकिंग सॉफ़्टवेयर में बैंक खाते कैसे बनाए जाते हैं (और वास्तव में, यह नहीं है कि बैंक वास्तविक दुनिया में कैसे काम करते हैं)। इसके बजाय, आपके पास एक लेन-देन पर्ची है, और एक खाते के लिए सभी लेनदेन पर्ची जोड़कर (और घटाकर) खाते की शेष राशि की गणना की जाती है। दूसरे शब्दों में: स्थानांतरण डेटा है और शेष एक ऑपरेशन है ! (दिलचस्प बात यह है कि यह आपके सिस्टम को पूरी तरह से कार्यात्मक बनाता है, क्योंकि आपको कभी भी बैलेंस को संशोधित करने की आवश्यकता नहीं होती है, आपके खाते की वस्तुओं और लेनदेन की वस्तुओं दोनों को कभी भी बदलने की आवश्यकता नहीं होती है, वे अपरिवर्तनीय हैं।)

आपके विशिष्ट प्रश्न के बारे में toString, मैं सहमत हूं। मैं एक Showable प्रकार के वर्ग के हास्केल समाधान को बहुत पसंद करता हूं । (स्काला हमें सिखाता है कि टाइप कक्षाएं ओओ के साथ खूबसूरती से फिट होती हैं।) समानता के साथ भी। समानता बहुत बार किसी वस्तु की संपत्ति नहीं होती बल्कि उस संदर्भ की होती है जिसमें वस्तु का उपयोग किया जाता है। फ्लोटिंग पॉइंट नंबरों के बारे में सोचें: एप्सिलॉन क्या होना चाहिए? फिर, हास्केल के पास Eqवर्ग है।


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

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

1
मैं यह नहीं कहूंगा कि क्रिया / संज्ञा पद्धति "हास्यास्पद" है। मैं कहूंगा कि सरलीकृत डिज़ाइन विफल हो जाएंगे और सही होना बहुत मुश्किल है। क्योंकि, counterexample, एक RESTful API एक Verb / Noun कार्यप्रणाली नहीं है? कहाँ, कठिनाई के एक अतिरिक्त डिग्री के लिए, क्रियाएं बेहद सीमित हैं?
user949300

@ user949300: यह तथ्य कि क्रियाओं का समूह नियत है, मैंने बताई गई समस्या को ठीक से टाल दिया, अर्थात आप कई अलग-अलग तरीकों से वाक्य बना सकते हैं, इस प्रकार एक संज्ञा क्या है और एक क्रिया लेखन शैली पर निर्भर है और डोमेन विश्लेषण नहीं ।
जर्ग डब्ल्यू मित्तग

8

सभी भी अक्सर सिंगल रिस्पॉन्सिबिलिटी प्रिंसिपल एक जीरो रिस्पांसिबिलिटी प्रिंसिपल बन जाते हैं, और आप एनीमिक क्लासेस के साथ समाप्त हो जाते हैं , जो कुछ नहीं करते ( बसने वालों और गेटर्स को छोड़कर), जो कि किंगडम ऑफ द नाउन्स डिजास्टर की ओर जाता है ।

आप इसे कभी भी परिपूर्ण नहीं कर पाएंगे, लेकिन एक वर्ग के लिए थोड़ा बहुत बहुत कम करने के लिए बेहतर है।

आप एनकोडिंग, IMO के साथ उदाहरण में, यह निश्चित रूप से सांकेतिक शब्दों में बदलना करने में सक्षम होना चाहिए। इसके बजाय आपको क्या करना चाहिए? बस एक नाम "utf" होना शून्य जिम्मेदारी है। अब, शायद नाम एनकोडर होना चाहिए। लेकिन, जैसा कि कोनराड ने कहा, डेटा (जो एन्कोडिंग) और व्यवहार (ऐसा करना) एक साथ हैं


7

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

यदि आप फ़ाइल में लिखने के लिए कुछ लिखना चाहते हैं, तो उन सभी चीजों के बारे में सोचें, जिन्हें आपको (ओएस पर) निर्दिष्ट करने की आवश्यकता है: फ़ाइल नाम, एक्सेस विधि (पढ़ें, लिखें, एपेंड करें), वह स्ट्रिंग जिसे आप लिखना चाहते हैं।

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

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

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

कुछ समस्याओं के शॉर्टकट समाधान में वस्तुओं की परस्पर स्थिति शामिल है, जो इतना कार्यात्मक नहीं है - आप बाहर से बंदियों में हेरफेर कर रहे हैं। आप अपनी कक्षा की कुछ चीजों को "वैश्विक" बना रहे हैं, कम से कम ऊपर के दायरे में। हर बार जब आप एक सेटर लिखते हैं - उन से बचने की कोशिश करें। मैं यह तर्क दूंगा कि आपको अपनी कक्षा, या अन्य वर्गों की जिम्मेदारी मिली है, जिसमें वह गलत है। लेकिन बहुत ज्यादा चिंता न करें - यह कुछ हद तक संज्ञानात्मक भार के बिना, जल्दी से कुछ प्रकार की समस्याओं को हल करने के लिए उत्परिवर्तित स्थिति में हलचल करने के लिए व्यावहारिक है।

तो संक्षेप में, अपने प्रश्न का उत्तर देने के लिए - एक वर्ग की वास्तविक जिम्मेदारी क्या है? यह कुछ अधिक अंतर्निहित प्रकार के ऑपरेशन को प्राप्त करने के लिए, कुछ अंतर्निहित डेटा के आधार पर, एक तरह का मंच पेश करना है। यह एक ऑपरेशन में शामिल आधे डेटा को एनकैप्सुलेट करना है जो डेटा के अन्य आधे से कम बार बदलता है (सोचो ...)। उदा। फ़ाइल नाम बनाम स्ट्रिंग लिखने के लिए।

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


4

मैं यह भी समझता हूं कि इसके लिए एक सटीक उत्तर (जो एक गंभीर उत्तर की तुलना में अधिक निबंध होगा) नहीं हो सकता है, या यह राय-आधारित हो सकता है। फिर भी मैं जानना चाहूंगा कि क्या मेरा दृष्टिकोण वास्तव में एकल-जिम्मेदारी सिद्धांत का अनुसरण करता है।

जबकि ऐसा होता है, यह जरूरी नहीं कि अच्छे कोड के लिए बना हो। इस सरल तथ्य से परे कि किसी भी प्रकार के नेत्रहीन नियम का पालन करने से बुरा कोड होता है, आप एक अमान्य आधार को शुरू कर रहे हैं: (प्रोग्रामिंग) ऑब्जेक्ट्स (भौतिक) ऑब्जेक्ट नहीं हैं।

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

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


4

मैं इस सी # कोड (इस पोस्ट में इस्तेमाल की जाने वाली चौथी वस्तु भाषा) को दूसरे दिन ही ले आया:

byte[] bytes = Encoding.Default.GetBytes(myString);
myString = Encoding.UTF8.GetString(bytes);

और मुझे लगता है कि यह मेरे लिए बहुत मायने नहीं रखता है कि एक Encodingया Charsetवर्ग वास्तव में तार एन्कोड करता है । यह केवल एक प्रतिनिधित्व होना चाहिए कि वास्तव में एन्कोडिंग क्या है।

सिद्धांत रूप में, हां, लेकिन मुझे लगता है कि सी # सादगी के लिए एक न्यायसंगत समझौता करता है (जैसा कि जावा के अधिक सख्त दृष्टिकोण के विपरीत है)।

यदि Encodingकेवल कुछ एन्कोडिंग का प्रतिनिधित्व (या पहचाना गया) - कहते हैं, UTF-8 - तो आपको स्पष्ट रूप से एक Encoderवर्ग की आवश्यकता होगी , ताकि आप उस GetBytesपर भी अमल कर सकें - लेकिन तब आपको Encoders और Encodings के बीच के संबंध को प्रबंधित करने की आवश्यकता होती है , इसलिए हम हमारे अच्छे राज के साथ अंत करें '

EncodersFactory.getDefaultFactory().createEncoder(new UTF8Encoding()).getBytes(myString)

बहुत शानदार ढंग से उस लेख में लिखा गया है जिसे आप (महान पढ़ें, वैसे) से जुड़ा हुआ है।

अगर मैं आपको अच्छी तरह से समझता हूं, तो आप पूछ रहे हैं कि लाइन कहां है।

ठीक है, स्पेक्ट्रम के विपरीत दिशा में प्रक्रियात्मक दृष्टिकोण है, स्थिर वर्गों के उपयोग के साथ OOP भाषाओं में लागू करना कठिन नहीं है:

HelpfulStuff.GetUTF8Bytes(myString)

इसके बारे में बड़ी समस्या यह है कि जब HelpfulStuffपत्तियों का लेखक और मैं मॉनिटर के सामने बैठा हूं, तो मुझे यह जानने का कोई तरीका नहीं है कि कहां GetUTF8Bytesलागू किया गया है।

मैं में ढूंढते है HelpfulStuff, Utils, StringHelper?

भगवान मेरी मदद करें अगर विधि वास्तव में उन तीनों में स्वतंत्र रूप से कार्यान्वित की जाती है ... जो बहुत कुछ होता है, यह सब लगता है कि मेरे सामने वाले व्यक्ति को यह नहीं पता था कि उस फ़ंक्शन को कहां देखना है, और माना कि कोई भी नहीं था अभी तक वे एक दूसरे को बाहर निकाल दिया और अब हम उन्हें बहुतायत में है।

मेरे लिए, उचित डिज़ाइन, संतोषजनक मानदंड के बारे में नहीं है, बल्कि आपके कोड के सामने बैठने के बाद ले जाने में मेरी आसानी के बारे में है। अब कैसे करता है

EncodersFactory.getDefaultFactory().createEncoder(new UTF8Encoding()).getBytes(myString)

इस पहलू में दर? बेचारा भी। जब मैं अपने काम करने वाले से चिल्लाता हूं तो यह जवाब नहीं देना चाहता कि "मैं एक बाइट अनुक्रम में एक स्ट्रिंग को कैसे एन्कोड करता हूं?" :)

इसलिए मैं उदारवादी दृष्टिकोण के साथ जाऊंगा और एकल जिम्मेदारी के बारे में उदार होऊंगा। मैं बल्कि Encodingकक्षा में दोनों प्रकार के एन्कोडिंग की पहचान करना और वास्तविक एन्कोडिंग करना होगा: व्यवहार से डेटा अनसेफर्ड।

मुझे लगता है कि यह एक मुखौटा पैटर्न के रूप में गुजरता है, जो गियर को चिकना करने में मदद करता है। क्या यह वैध पैटर्न SOLID का उल्लंघन करता है? एक संबंधित प्रश्न: क्या मुखौटा पद्धति SRP का उल्लंघन करती है?

ध्यान दें कि यह हो सकता है कि इनकोडिंग बाइट्स आंतरिक रूप से (.NET लाइब्रेरी में) कार्यान्वित हों। कक्षाएं केवल सार्वजनिक रूप से दिखाई नहीं देती हैं और केवल यह "मुखर" एपीआई बाहर उजागर होता है। यह सत्यापित करना कठिन नहीं है कि क्या सच है, मैं अभी इसे करने के लिए थोड़ा बहुत आलसी हूँ :) यह शायद नहीं है, लेकिन यह मेरी बात को अमान्य नहीं करता है।

आप आंतरिक रूप से अधिक गंभीर, विहित कार्यान्वयन को लागू करते हुए मित्रता के लिए सार्वजनिक रूप से दृश्यमान कार्यान्वयन को सरल बनाने का विकल्प चुन सकते हैं।


1

जावा में फ़ाइलों का प्रतिनिधित्व करने के लिए उपयोग किया जाने वाला अमूर्त एक धारा है, कुछ धाराएँ एक-दिशात्मक (केवल पढ़ने या लिखने के लिए) हैं, जबकि अन्य द्वि-दिशात्मक हैं। रूबी के लिए फ़ाइल वर्ग एब्सट्रैक्शन है जो ओएस फ़ाइलों का प्रतिनिधित्व करता है। तो सवाल बन जाता है कि इसकी अकेली जिम्मेदारी क्या है? जावा में, FileWriter की जिम्मेदारी बाइट्स की एक यूनिडायरेक्शनल स्ट्रीम प्रदान करना है जो OS फ़ाइल से जुड़ी है। रूबी में, फ़ाइल की जिम्मेदारी सिस्टम फ़ाइल के लिए द्विदिश पहुंच प्रदान करना है। वे दोनों एसआरपी को पूरा करते हैं, उनके पास बस अलग-अलग जिम्मेदारियां हैं।

यह एक कार या एक कुत्ते की जिम्मेदारी नहीं है कि वह खुद को एक स्ट्रिंग में बदल दे, अब यह है?

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

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


0

कक्षा में कई जिम्मेदारियां हो सकती हैं। कम से कम क्लासिक डेटा-केंद्रित OOP में।

यदि आप एकल जिम्मेदारी सिद्धांत को उसकी पूर्ण सीमा तक लागू कर रहे हैं, तो आपको जिम्मेदारी-केंद्रित डिजाइन मिलता है जहां मूल रूप से प्रत्येक गैर-सहायक विधि अपने वर्ग से संबंधित होती है।

मुझे लगता है कि फ़ाइल और FileWriter के मामले में एक आधार वर्ग से जटिलता का एक टुकड़ा निकालने में कुछ भी गलत नहीं है। लाभ यह है कि आपको एक अलग संचालन के लिए जिम्मेदार कोड का स्पष्ट पृथक्करण मिलता है और यह भी कि आप पूरे आधार वर्ग (जैसे फ़ाइल) को ओवरराइड करने के बजाय कोड के उस टुकड़े को (उपवर्ग) ओवरराइड कर सकते हैं। फिर भी, व्यवस्थित रूप से इसे लागू करना मेरे लिए एक मुश्किल है। आपको बस संभालने के लिए बहुत अधिक कक्षाएं मिलती हैं और प्रत्येक ऑपरेशन के लिए आपको इसकी संबंधित कक्षा को लागू करना होगा। यह लचीलापन है जो कुछ कीमत पर आता है।

ये निकाला वर्गों आपरेशन वे होते हैं, जैसे के आधार पर बहुत वर्णनात्मक नाम होना चाहिए <X>Writer, <X>Reader, <X>Builder। नाम पसंद करते हैं <X>Manager, <X>Handlerऑपरेशन का वर्णन बिल्कुल नहीं करते हैं और अगर उन्हें इस तरह कहा जाता है क्योंकि उनमें एक से अधिक ऑपरेशन होते हैं, तो यह स्पष्ट नहीं है कि आपने क्या हासिल किया है। आपने इसके डेटा से कार्यक्षमता को अलग कर दिया है, आप अभी भी उस निकाले गए वर्ग में एकल जिम्मेदारी सिद्धांत को तोड़ते हैं, और यदि आप एक निश्चित विधि की तलाश कर रहे हैं, तो आप यह नहीं जान सकते कि इसे कहाँ देखना है (यदि में <X>या तो <X>Manager)।

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

आपने शायद UserDataHandler को इस तरह नामित किया है क्योंकि मूल रूप से उस वर्ग में केवल कार्यक्षमता है और कोई वास्तविक डेटा नहीं है। हालाँकि, आप उस तथ्य से भी अलग हो सकते हैं और डेटाबेस में डेटा को वर्ग से संबंधित मान सकते हैं। इस अमूर्त के साथ आप यह क्या है और क्या नहीं के आधार पर वर्ग का नाम दे सकते हैं । आप इसे UserRepository जैसा नाम दे सकते हैं, जो बहुत ही स्लीक है और रिपॉजिटरी पैटर्न के उपयोग का भी सुझाव देता है ।

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