2012-04-30 18 views
5

"Tell, don't Ask"-principle के बाद किसी को ओओपी में गेटर्स का उपयोग नहीं करना चाहिए।ओओपी - बिना जीईटी/एसईटी

लेकिन समस्याएं कैसे हल करें (कम से कम मुझे ऐसा लगता है) वास्तव में किसी वस्तु से कुछ "जानकारी के अंदर" की आवश्यकता होती है? तो निम्न उदाहरण को कैसे बदलें ताकि create_bill() फ़ंक्शन को प्रत्येक आइटम के लिए मूल्य के लिए ASK की आवश्यकता नहीं है?

class chopping_cart { 

    private $itemlist = array(); 

    function item_add($name, $price) { 
     $his->itemlist[]=new item($name, $price); 
    } 
    private create_bill() { 

     foreach $this->itemlist AS $element; 
     $sum += $element->get_price(); 

    } 
} 


class item { 
    private $name; 
    private $price; 
    function __construcor($name,$price) {...} 
    function get_price() { 
     return $price; 
    } 
} 

उपयोग:

$sc = new shopping_cart() 
$sc->item_add("Bike", 1.00); 
$sc->item_add("Ship", 2.00); 
$sc->create_bill(); 
+0

यदि एक शॉपिंग कार्ट में सामानों की सूची है, तो शॉपिंग कार्ट प्रत्येक आइटम की कीमत के मूल्य को जानने में सक्षम क्यों है? – user12345613

+1

"बताओ मत पूछो" के बाद - शिष्य यह बुरा लगता है। – Tom

+0

आपने यह कहां सुना "सिद्धांत मत पूछो" सिद्धांत? मैंने इसके हारे में नहीं सुना है। – xxpor

उत्तर

7

अनुरोधित डेटा/राज्य का उपयोग नहीं कर रहे हैं वस्तु आप के लिए, मुझे नहीं लगता कि संदर्भ दे रहे बदलने के लिए कुछ भी सब पर टिककर खेल का उपयोग कर के साथ गलत क्या है ।

इस तरह एक परिदृश्य के बारे में सिद्धांत वार्ता:

if ($item->get_price() < 5) { 
    $item->set_price(5); 
} 

$item->set_minimum_price(5) की तरह कुछ में तब्दील किया जा चाहिए।

4

आपको लगता है कि भालू गहन छानबीन की संदर्भ दे रहे "Tell, Don't Ask" लेख से दो आइटम हैं:

  1. [...] मत पूछो [वस्तुओं] अपने राज्य के बारे में सवाल, एक निर्णय करते हैं , और फिर उन्हें बताएं कि क्या करना है।
    अपने विशेष उदाहरण के साथ, chopping_cart केवल वस्तुओं को पूछताछ & निर्णय लेता है। महत्वपूर्ण बात यह है कि यह नहीं कहता कि क्या करना है।
  2. अनुबंध द्वारा डिजाइन के अनुसार, जब तक आपकी विधियों (प्रश्नों और आदेशों) को स्वतंत्र रूप से अंतःस्थापित किया जा सकता है, और ऐसा करके कक्षा परिवर्तक का उल्लंघन करने का कोई तरीका नहीं है, तो आप ठीक हैं। लेकिन जब आप क्लास इनवेरिएंट को बनाए रखते हैं, तो आपने कॉलर और कैली के बीच युग्मन में नाटकीय रूप से वृद्धि की हो सकती है, इस पर निर्भर करता है कि आपने कितना राज्य उजागर किया है।
    गेटर कॉल आम तौर पर स्वतंत्र रूप से अंतःस्थापित हो सकते हैं, इसलिए क्लास इनवेरिएंट को बनाए रखने की आवश्यकता के कारण कोई युग्मन नहीं होता है।

इस प्रकार, गेटर्स उन मुद्दों का कारण नहीं बनते हैं जो "बताओ, मत पूछें" सिद्धांत को रोकने के लिए माना जाता है।

2

आप इस मामले में Visitor design pattern का उपयोग कर सकते हैं। आपके Product वर्ग में addToBill विधि लागू करें और तर्क के रूप में एक उदाहरण पास करें जो आपके बिल इंटरफ़ेस को लागू करता है, IBillIBill एक विधि addToTotal का समर्थन करता है जो आइटम में उपलब्ध सभी आवश्यक जानकारी स्वीकार करेगा; आपके मामले में, यह एक कीमत है। उदाहरण के लिए:

interface IBill { 
    /* needs to be public because PHP doesn't understand the concept of 
     friendship 
    */ 
    function addToTotal($price); 
} 

class Bill implements IBill { 
    private $total = 0; 

    function addToTotal($price) { 
     $this->total += $price; 
    } 
    ... 
} 

class ShoppingCart { 
    private $items = array(); 

    function addItem($id, $product, $quantity) { 
     if (isset($this->items[$id])) { 
      $this->items[$id]->addQuantity($quantity); 
     } else { 
      $this->items[$id] = new LineItem($product, $quantity); 
     } 
    } 

    private createBill() { 
     $bill = new Bill; 
     foreach ($this->items AS $lineItem) { 
      $lineItem->addToBill($bill); 
     } 
     return ...; 
    } 
} 

class LineItem { 
    private $product, $quantity; 
    function __constructor($product, $quantity) {...} 
    function addToBill(IBill $bill) { 
     $this->product->addToBill($bill, $quantity); 
    } 
    function addQuantity($quantity) { 
     $this->quantity += $quantity; 
    } 
    ... 
} 

class Product { 
    private $name, $description, $price; 
    function __constructor(...) {...} 
    function addToBill(IBill $bill, $quantity) { 
     $bill->addToTotal($this->price * $quantity); 
    } 
    ... 
} 

हालांकि, आप हमेशा कमजोर जमीन पर उड़ जाएंगे। उपरोक्त को addToTotal जैसी विधि की आवश्यकता होती है, जो एक आविष्कार (कुल पंक्ति वस्तु मूल्यों और मात्राओं के उत्पादों के योग से मेल खाना चाहिए) का परिचय देता है, केवल "बताओ, मत पूछो" से बचने के लिए कहा जाता है। आप बिना addToTotal: * Bill के साथ इसे करने का प्रयास कर सकते हैं; ShoppingCart कुल का ट्रैक रखता है। उत्पाद & मात्रा के अतिरिक्त मूल्य को addItem पर पास करें; addItem कुल अद्यतन। यह कक्षाओं के उद्देश्य को कुछ हद तक हरा देता है, क्योंकि आप LineItem या Product का उपयोग नहीं कर रहे हैं।यह एक आविष्कार भी जोड़ता है कि उत्तीर्ण मूल्य और उत्पाद बनाया गया था जब मूल्य बनाया जाना चाहिए, हालांकि यदि वे नहीं करते हैं, तो यह मुद्दों का कारण नहीं बनना चाहिए (यह केवल अजीब होगा)। * addItemProduct और LineItem को तत्काल करें; addItem कुल अद्यतन। पहले जोड़े गए अतिरिक्त आइटम जोड़ते समय, या तो एक अतिरिक्त आविष्कार होना चाहिए कि पास-इन $price को पिछली कॉल में पारित राशि से मेल खाना चाहिए, या addItem को अतिरिक्त, मौजूदा आइटम जोड़ने की अनुमति नहीं दी जा सकती है। * सभी वस्तुओं को एक साथ दूर करें। ShoppingCart उत्पाद आईडी और मात्रा को स्टोर करता है। addItem पर प्रत्येक कॉल कुल अपडेट करता है। createBill पहले से गणना की गई कुल का उपयोग करता है। दूसरों की तुलना में भी अधिक, यह separate concerns को एकजुट करता है।

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

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