2011-09-13 14 views
6

मैं एक मूल्य वस्तु के रूप में Address मॉडल करना चाहता हूं। चूंकि यह अपरिवर्तनीय बनाने के लिए एक अच्छा अभ्यास है, इसलिए मैंने कोई भी सेटटर प्रदान नहीं करना चुना, जो बाद में इसे संशोधित करने की अनुमति दे सकता है।डीडीडी: एक जटिल मूल्य वस्तु को अपरिवर्तनीय कैसे रखा जाए?

एक आम तरीका है कि डेटा को कन्स्ट्रक्टर को पास करना; तथापि, जब मूल्य वस्तु बहुत बड़ी है, कि काफी फूला हुआ हो सकता है:

class Address { 
    public function __construct(
     Point $location, 
     $houseNumber, 
     $streetName, 
     $postcode, 
     $poBox, 
     $city, 
     $region, 
     $country) { 
     // ... 
    } 
} 

एक और दृष्टिकोण एक साफ निर्माता है, जिसके परिणामस्वरूप एक सरणी के रूप में तर्क प्रदान करने के लिए, हो whould, लेकिन यह हो सकता है गंदगी के कार्यान्वयन कन्स्ट्रक्टर:

class Address { 
    public function __construct(array $parts) { 
     if (! isset($parts['location']) || ! $location instanceof Point) { 
      throw new Exception('The location is required'); 
     } 
     $this->location = $location; 
     // ... 
     if (isset($parts['poBox'])) { 
      $this->poBox = $parts['poBox']; 
     } 
     // ... 
    } 
} 

यह मेरे लिए थोड़ा अप्राकृतिक दिखता है।

किसी भी बड़े मूल्य वस्तु को सही ढंग से कार्यान्वित करने के तरीके पर कोई सलाह?

+1

व्यक्तिगत रूप से मुझे लगता है कि यदि आपकी मान वस्तु इतनी बड़ी है कि इससे समस्याएं आती हैं, तो इसे कई मूल्य वस्तुओं में विभाजित करने की आवश्यकता होती है। पता उदाहरण मेरी व्यक्तिगत संवेदनशीलताओं के लिए ठीक लगता है, लेकिन यदि आपको यह बहुत बड़ा लगता है तो शायद यह स्थान + सड़क का पता + शहर (जहां शहर क्षेत्र और देश शामिल हो) हो सकता है। – Domenic

+0

@Domenic: यह भी एक दिलचस्प दृष्टिकोण है! – Benjamin

उत्तर

12

large list of parameters के साथ मुख्य समस्या पठनीयता और खतरे है कि आप पैरामीटर को मिश्रित करेंगे। Effective Java में वर्णित अनुसार आप Builder pattern के साथ इन समस्याओं से निपट सकते हैं।

public class AddressBuilder { 
    private Point _point; 
    private String _houseNumber; 

    // other parameters 

    public AddressBuilder() { 
    } 

    public AddressBuilder WithPoint(Point point) { 
     _point = point; 
     return this; 
    } 

    public AddressBuilder WithHouseNumber(String houseNumber) { 
     _houseNumber = houseNumber; 
     return this; 
    } 

    public Address Build() { 
     return new Address(_point, _houseNumber, ...); 
    } 
} 

Address address = new AddressBuilder() 
    .WithHouseNumber("123") 
    .WithPoint(point) 
    .Build(); 

फायदे::

  • पैरामीटर नाम हैं तो यह अधिक पठनीय
  • कठिन अप मिश्रण है यह कोड अधिक पठनीय (विशेष रूप से भाषा है कि नामित समर्थन नहीं और वैकल्पिक पैरामीटर) बनाता है
  • मापदंडों के अपने खुद के आदेश का उपयोग कर सकते क्षेत्र के साथ घर का नंबर
  • वैकल्पिक पैरामीटर छोड़ा जा सकता है

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

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

public class Address { 
    private readonly String _streetName; 
    private readonly String _houseNumber; 

    ... 

    public Address WithNewStreetName(String newStreetName) { 
     // enforce street name rules (not null, format etc) 

     return new Address(
      newStreetName 
      // copy other members from this instance 
      _houseNumber); 
    } 

    ... 
} 
+0

बहुत ही रोचक जवाब, धन्यवाद। क्या हम एक कारखाने को भी कहते हैं, या कारखाने पैटर्न संस्थाओं के लिए आरक्षित है? – Benjamin

+0

डीडीडी फैक्ट्री का उपयोग जटिल मूल्य वस्तुओं के निर्माण के लिए किया जा सकता है। इस बिल्डर को डीडीडी फैक्ट्री माना जा सकता है। – Dmitry

+0

यह उत्तर सही है! – jpierson

-1

अपरिवर्तनीय समवर्ती गणना, कोई अवरोधित करना और कोई लॉक के लिए फिट है, अपरिवर्तनीय उच्च प्रदर्शन और अच्छा scalability के लिए है।

तो वैल्यू ऑब्जेक्ट एक समवर्ती प्रणाली में बेहतर चल रहा है, वितरण प्रणाली में शामिल हो सकता है, पुराने वीओ को नए वीओ के साथ प्रतिस्थापित कर सकता है, कोई ज़रूरत नहीं है, इसलिए कोई अवरोध नहीं है।

0

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

दूसरा
आप पैरामीटर को वैल्यू ऑब्जेक्ट्स के रूप में समूहित करना शुरू कर सकते हैं। आप एक सिटी वैल्यू ऑब्जेक्ट बना सकते हैं। इसके लिए शहर, क्षेत्र/राज्य और देश की आवश्यकता हो सकती है। मुझे लगता है कि जब तक मैं क्षेत्र और देश को नहीं जानता, तब तक शहर का नाम बहुत अधिक नहीं होता है। पेरिस का मतलब पेरिस, इलिनोइस, यूएस या पेरिस, आइल-डी-फ्रांस, एफआर के अलावा कुछ भी नहीं है, आपको एक पूरी तस्वीर देता है। इसलिए यह पता ऑब्जेक्ट पर गिनती पैरामीटर गिनती को भी कम करेगा।

यदि आप नीचे जाते हैं तो डीडीडी रोड उस डोमेन के लिए एक डोमेन विशेषज्ञ ढूंढता है जिसके लिए आप कोडिंग कर रहे हैं, आपको विशेषज्ञ नहीं होना चाहिए। कभी-कभी समस्याओं को कोड या निफ्टी डिजाइन पैटर्न द्वारा तय नहीं किया जाना चाहिए।

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