2015-06-16 6 views
6

मुझे यकीन है कि मेरी कक्षा के अंदर इस विधि एकल जिम्मेदारी सिद्धांत का उल्लंघन किया गया है या नहीं हूँ,सॉलिड - क्या एकल जिम्मेदारी सिद्धांत कक्षा में विधियों पर लागू होता है? डालने या अद्यतन -

public function save(Note $note) 
{ 
    if (!_id($note->getid())) { 

     $note->setid(idGenerate('note')); 

     $q = $this->db->insert($this->table) 
         ->field('id', $note->getid(), 'id'); 

    } else { 
     $q = $this->db->update($this->table) 
         ->where('AND', 'id', '=', $note->getid(), 'id'); 
    } 

    $q->field('title', $note->getTitle()) 
     ->field('content', $note->getContent()); 

    $this->db->execute($q); 

    return $note; 
} 

मूल रूप से यह दो नौकरियां एक विधि में करता है।

क्या मुझे अलग अलग-अलग जिम्मेदारी सिद्धांत का अनुपालन करने के बजाय इसे दो तरीकों से अलग करना चाहिए?

लेकिन एसआरपी कक्षाओं के लिए केवल है, है ना? क्या यह कक्षा के अंदर विधियों पर लागू होता है?

SRP -

एक वर्ग में केवल एक ही जिम्मेदारी है (यानी केवल एक सॉफ्टवेयर के विनिर्देश में संभावित परिवर्तन में सक्षम होना चाहिए करने के लिए वर्ग के विनिर्देश को प्रभावित) चाहिए

संपादित करें:

नोट्स सूचीबद्ध करने के लिए एक और तरीका (कई अलग-अलग प्रकार की लिस्टिंग सहित), खोज n OTES, आदि ...

public function getBy(array $params = array()) 
{ 
    $q = $this->db->select($this->table . ' n') 
        ->field('title') 
        ->field('content') 
        ->field('creator', 'creator', 'id') 
        ->field('created_on') 
        ->field('updated_on'); 

    if (isset($params['id'])) { 
     if (!is_array($params['id'])) { 
      $params['id'] = array($params['id']); 
     } 

     $q->where('AND', 'id', 'IN', $params['id'], 'id'); 
    } 

    if (isset($params['user_id'])) { 
     if (!is_array($params['user_id'])) { 
      $params['user_id'] = array($params['user_id']); 
     } 

     # Handling of type of list: created/received 
     if (isset($params['type']) && $params['type'] == 'received') { 
      $q 
       ->join(
        'inner', 
        $this->table_share_link . ' s', 
        's.target_id = n.id AND s.target_type = \'note\'' 
       ) 
       ->join(
        'inner', 
        $this->table_share_link_permission . ' p', 
        'p.share_id = s.share_id' 
       ) 
       # Is it useful to know the permission assigned? 
       ->field('p.permission') 
       # We don't want get back own created note 
       ->where('AND', 'n.creator', 'NOT IN', $params['user_id'], 'uuid'); 
      ; 

      $identity_id = $params['user_id']; 

      # Handling of group sharing 
      if (isset($params['user_group_id']) /*&& count($params['user_group_id'])*/) { 
       if (!is_array($params['user_group_id'])) { 
        $params['user_group_id'] = array($params['user_group_uuid']); 
       } 

       $identity_id = array_merge($identity_id, $params['user_group_id']); 
      } 

      $q->where('AND', 'p.identity_id', 'IN', $identity_id, 'id'); 

     } else { 
      $q->where('AND', 'n.creator', 'IN', $params['user_id'], 'id'); 
     } 
    } 

    # If string search by title 
    if (isset($params['find']) && $params['find']) { 
     $q->where('AND', 'n.title', 'LIKE', '%' . $params['find'] . '%'); 
    } 

    # Handling of sorting 
    if (isset($params['order'])) { 
     if ($params['order'] == 'title') { 
      $orderStr = 'n.title'; 

     } else { 
      $orderStr = 'n.updated_on'; 
     } 

     if ($params['order'] == 'title') { 
      $orderStr = 'n.title'; 

     } else { 
      $orderStr = 'n.updated_on'; 
     } 

     $q->orderBy($orderStr); 

    } else { 
     // Default sorting 
     $q->orderBy('n.updated_on DESC'); 
    } 

    if (isset($params['limit'])) { 
     $q->limit($params['limit'], isset($params['offset']) ? $params['offset'] : 0); 
    } 

    $res = $this->db->execute($q); 

    $notes = array(); 

    while ($row = $res->fetchRow()) { 
     $notes[$row->uuid] = $this->fromRow($row); 
    } 

    return $notes; 
} 

उत्तर

12

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

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

exempli अनुग्रह राशि: यदि आप कभी कभी insert या update जो भी कारण के लिए स्पष्ट रूप से कॉल करने के लिए की जरूरत

public function save(Note $note) { 
    if (..) { 
     $this->insert($note); 
    } else { 
     $this->update($note); 
    } 
} 

public function insert(Note $note) { 
    .. 
} 

public function update(Note $note) { 
    .. 
} 

ऊपर मतलब होगा। एसआरपी वास्तव में इस अलगाव के लिए एक कारण नहीं है।

+0

धन्यवाद। उपरोक्त मेरे संपादन में विधि के बारे में क्या। यह उदाहरण के लिए एक ही समय में नोट्स और खोज नोट्स सूचीबद्ध करने के लिए है। क्या ऐसा करना ठीक है या क्या मुझे उन्हें अलग करना चाहिए? क्या यह एसआरपी का उल्लंघन कर रहा है? – laukok

+1

ठीक है, उस विधि की ज़िम्मेदारी खोज मानदंडों की एक श्रृंखला लेना और नोटों की एक सूची वापस करना है। यह हमेशा एक ही बात है। यहां तक ​​कि यदि कार्यान्वयन अपेक्षाकृत जटिल हो सकता है और संभवतः स्वच्छता के लिए अलग-अलग तरीकों से दोबारा प्रतिक्रिया दी जा सकती है, तो एसआरपी का उल्लंघन नहीं होता है। संक्षेप में एसआरपी का मतलब है कि आपको यह वर्णन करने में सक्षम होना चाहिए कि एक विधि/वर्ग/मॉड्यूल एक छोटी सी वाक्य में क्या करता है। जैसे ही आपको इसका वर्णन करने की आवश्यकता है * यह एक्स foo, bar, baz करता है और यह कॉफी * बनाता है, यह शायद एसआरपी का उल्लंघन कर रहा है। – deceze

+1

* "तर्क एक्स लेता है और परिणाम वाई देता है" * एक जिम्मेदारी है। * बहुत अधिक * का एक उदाहरण होगा: * "यह वर्ग डेटाबेस कनेक्शन प्रबंधित करता है, और डेटा को क्रमबद्ध करता है, और टेम्पलेट प्रस्तुत करता है, और प्रतिक्रिया को कैश करता है" *। – deceze

1

सोलिड सिद्धांत कक्षा-स्तर की शब्दावली पर लागू होते हैं, वे स्पष्ट रूप से विधियों के बारे में नहीं बताते हैं। एक एसआरपी स्वयं ही कहता है कि कक्षाओं में बदलाव का एक कारण होना चाहिए, इसलिए जब तक आप एक वर्ग में लिपटे एक जिम्मेदारी को प्रतिस्थापित कर सकें, तो आप ठीक हैं।

इस पर विचार करें:

$userMapper = new Mapper\MySQL(); 
// or 
$userMapper = new Mapper\Mongo(); 
// or 
$userMapper = new Mapper\ArangoDb(); 

$userService = new UserService($userMapper); 

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

आपका मामला आम तौर पर एसआरपी के बारे में नहीं है। यह सर्वोत्तम अभ्यास के बारे में अधिक है।खैर, तरीकों के बारे में सबसे अच्छा अभ्यास बताता है कि जब भी संभव हो, उन्हें केवल एक चीज करना चाहिए और यथासंभव कम तर्क के रूप में स्वीकार करना चाहिए। इससे बग को पढ़ने और ढूंढना आसान हो जाता है।

एक और सिद्धांत है जिसे Principle of Least Astonishment कहा जाता है। यह बस बताता है कि विधि नामों को स्पष्ट रूप से करना चाहिए जो उनके नामों का अर्थ है।

अपने कोड उदाहरण के लिए नीचे आ रहा है:

save() संकेत मिलता है कि यह सब के बारे में डेटा की बचत (मौजूदा रिकॉर्ड को अपडेट करने), बनाने नहीं है। वहां सम्मिलित और अद्यतन दोनों करके, आप पोला तोड़ते हैं।

यह है कि, जब आप स्पष्ट रूप से insert() पर कॉल करते हैं तो आप जानते हैं और उम्मीद करते हैं कि यह एक नया रिकॉर्ड जोड़ देगा। update() विधि के बारे में वही - आप जानते हैं और उम्मीद करते हैं कि यह एक विधि अपडेट करेगा, यह एक नया निर्माण नहीं करेगा।

इसलिए मैं save() में दोनों चीजें नहीं करूँगा। अगर मैं एक रिकॉर्ड अपडेट करना चाहता हूं, तो मैं update() पर कॉल करूंगा। अगर मैं एक रिकॉर्ड बनाना चाहता हूं तो मैं insert() पर कॉल करूंगा।

+0

मैं असहमत हूं कि 'सेव' का अर्थ केवल सम्मिलित या अपडेट करना है। मेरे लिए 'सेव' 'स्थिर 'के बराबर है, इस मामले में मुझे परवाह नहीं है कि अंतर्निहित कार्यान्वयन क्या करता है, केवल तभी जब मैं इसके लिए पूछूं तो मैं उस डेटा को फिर से प्राप्त कर पाऊंगा। – deceze

+0

@deceze आप PoLS के संबंध में 'save() 'पर कैसे टिप्पणी करेंगे? और अलगाव में परीक्षण करते समय, क्या यह अभी भी बेहतर होगा (अपेक्षाओं और पठनीयता के मामले में) 2 विधियों 'डालने() 'और' अपडेट() 'से? – Yang

+0

एक ऐसा शब्द है जो इस ऑपरेशन के लिए बहुत आम है: अपरर्ट करें। मुझे नहीं पता कि क्या कोई भी अपवाद से आश्चर्यचकित हो गया है। मैं आपकी तरफ से बहस करता हूं कि 'सेव' का वर्तमान कार्यान्वयन ध्वनि नहीं है (इस बात पर आधारित है कि ऑब्जेक्ट में आईडी है या नहीं, यह कि यह आईडी वास्तव में डेटाबेस में मौजूद है या नहीं), लेकिन ऑपरेशन स्वयं ही सरल और आत्म व्याख्यात्मक है यदि आप डेटाबेस को एक सार वस्तु भंडारण के रूप में देखते हैं। – deceze

संबंधित मुद्दे

 संबंधित मुद्दे