समुच्चय के बीच संदर्भों के सत्यापन का इलाज कैसे करें?


11

मैं समुच्चय के बीच संदर्भ के साथ थोड़ा संघर्ष कर रहा हूं। आइए मान लें कि एग्रीगेट के Carपास एग्रीगेट का संदर्भ है Driver। इस संदर्भ को होने से मॉडल किया जाएगा Car.driverId

अब मेरी समस्या यह है कि मुझे एक Carकुल के सृजन को मान्य करने के लिए कितनी दूर जाना चाहिए CarFactory। क्या मुझे भरोसा करना चाहिए कि पारित DriverIdएक मौजूदा को संदर्भित करता है Driverया मुझे उस अपरिवर्तनीय की जांच करनी चाहिए?

जाँच के लिए, मुझे दो संभावनाएँ दिखती हैं:

  • मैं एक पूर्ण चालक इकाई को स्वीकार करने के लिए कार कारखाने के हस्ताक्षर को बदल सकता था। फैक्ट्री तो बस उस इकाई से आईडी लेगी और उसी के साथ कार का निर्माण करेगी। यहाँ पर आवेग की जाँच की जाती है।
  • मैं के लिए एक संदर्भ हो सकता था DriverRepositoryमें CarFactoryऔर स्पष्ट रूप से कहते हैं driverRepository.exists(driverId)

लेकिन अब मैं सोच रहा हूँ कि बहुत ज्यादा नहीं है? मैं सोच सकता था कि वे समुच्चय अलग-अलग बंधे हुए संदर्भ में रह सकते हैं, और अब मैं कार BC को DriverRepository या ड्राइवर BC के चालक इकाई पर निर्भरता के साथ प्रदूषित करूंगा।

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

जवाबों:


6

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

यह दृष्टिकोण आपको आकर्षक लग रहा है क्योंकि आपको मुफ्त में चेक मिलता है और यह सर्वव्यापी भाषा के साथ अच्छी तरह से जुड़ा हुआ है। A Carद्वारा संचालित नहीं है driverId, लेकिन a से Driver

यह दृष्टिकोण वास्तव में वॉन वर्नॉन द्वारा उपयोग किया गया है, यह पहचान और एक्सेस नमूना बाध्य संदर्भ है जहां वह एक Userकुल को पारित करता है Group, लेकिन Groupकेवल एक मूल्य प्रकार रखता है GroupMember। जैसा कि आप देख सकते हैं कि यह उपयोगकर्ता की सक्षमता की जांच करने की भी अनुमति देता है (हम अच्छी तरह जानते हैं कि चेक बासी हो सकता है)।

    public void addUser(User aUser) {
        //original code omitted
        this.assertArgumentTrue(aUser.isEnabled(), "User is not enabled.");

        if (this.groupMembers().add(aUser.toGroupMember()) && !this.isInternalGroup()) {
            //original code omitted
        }
    }

हालाँकि, Driverउदाहरण के द्वारा आप अपने आप को Driverभीतर के एक आकस्मिक संशोधन के लिए खोलते हैं Car। पासिंग वैल्यू रेफरेंस प्रोग्रामर के दृष्टिकोण से परिवर्तनों के बारे में तर्क करना आसान बनाता है, लेकिन एक ही समय में, डीडीडी सर्वव्यापी भाषा के बारे में है, इसलिए शायद यह जोखिम के लायक है।

यदि आप वास्तव में इंटरफ़ेस अलगाव सिद्धांत (ISP) को लागू करने के लिए अच्छे नामों के साथ आ सकते हैं तो आप एक ऐसे इंटरफ़ेस पर भरोसा कर सकते हैं जिसमें व्यवहार विधियां नहीं हैं। आप शायद एक वैल्यू ऑब्जेक्ट कॉन्सेप्ट के साथ भी आ सकते हैं जो एक अपरिवर्तनीय ड्राइवर संदर्भ का प्रतिनिधित्व करता है और जिसे केवल मौजूदा ड्राइवर (जैसे DriverDescriptor driver = driver.descriptor()) से ही इंस्टेंट किया जा सकता है ।

मैं सोच सकता था कि वे समुच्चय अलग-अलग बंधे हुए संदर्भ में रह सकते हैं, और अब मैं कार BC को DriverRepository या ड्राइवर BC के चालक इकाई पर निर्भरता के साथ प्रदूषित करूंगा।

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

इसलिए, आपके पास DriverLookupServiceकार-चालक संघों के प्रबंधन के लिए बीसी के रूप में परिभाषित हो सकता है । यह सेवा ड्राइवर प्रबंधन संदर्भ द्वारा उजागर की गई एक वेब-सेवा कह सकती है जो Driverऐसे उदाहरण देती है जो इस संदर्भ में मूल्य की वस्तुओं की सबसे अधिक संभावना होगी।

ध्यान दें कि बीसी के बीच वेब-सेवाओं के लिए आवश्यक रूप से सबसे अच्छा पृथक्करण विधि नहीं है। उदाहरण के लिए UserCreated, आप ड्राइवर के संदर्भ से संदेश का भी उपयोग कर सकते हैं, जो दूरस्थ संदर्भ में भस्म हो जाएगा, जो कि ड्राइवर का प्रतिनिधित्व स्वयं DB में संग्रहीत करेगा। DriverLookupServiceतो इस्तेमाल कर सकते हैं इस DB और ड्राइवर का डेटा आगे संदेश (उदा के साथ तारीख तक रखा जाएगा DriverLicenceRevoked)।

मैं वास्तव में आपको नहीं बता सकता कि कौन सा दृष्टिकोण आपके डोमेन के लिए बेहतर है, लेकिन उम्मीद है कि इससे आपको निर्णय लेने के लिए पर्याप्त अंतर्दृष्टि मिलेगी।


3

जिस तरह से आप सवाल पूछ रहे हैं (और दो विकल्पों का प्रस्ताव) यह ऐसा है जैसे कि केवल चिंता यह है कि कार के निर्माण के समय ड्राइवरआईड अभी भी वैध है।

हालाँकि, आपको यह भी चिंतित होना चाहिए कि कार को या तो डिलीट करने से पहले ड्राइवरआईड से जुड़े ड्राइवर को डिलीट नहीं किया जाता है या किसी अन्य ड्राइवर को दिया जाता है (और संभवतः यह भी कि ड्राइवर को किसी अन्य कार को नहीं सौंपा गया है (यदि डोमेन केवल ड्राइवर को प्रतिबंधित करता है) एक कार से जुड़ा होना))।

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

Btw, मैं @PriceJones से सहमत हूं कि कार और ड्राइवर के बीच का संबंध शायद कार या ड्राइवर से अलग एक जिम्मेदारी है। इस तरह का जुड़ाव केवल समय के साथ जटिलता में बढ़ेगा, क्योंकि यह एक शेड्यूलिंग प्रॉब्लम (ड्राइवर, कार, टाइम स्लॉट / विंडो, सब्स्टीट्यूट आदि) की तरह लगता है। भले ही यह एक रजिस्ट्रेशन प्रॉब्लम की तरह हो, एक को ऐतिहासिक चाहिए। पंजीकरण और साथ ही वर्तमान पंजीकरण। इस प्रकार, यह बहुत अच्छी तरह से अपने ई.पू.

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

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

कार और ड्राइवर का समय निर्धारण ई.पू. तो कुछ समय अवधि / अवधि, अब और भविष्य के लिए कार से जुड़े ड्राइवरों के एक कैलेंडर को बनाए रखता है, और एक अनुसूचित कार या ड्राइवर के अंतिम उपयोग पर केवल अन्य बीसी के व्यवहार का उल्लेख करता है।


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


2

मान लीजिए कि कुल कार में कुल चालक का संदर्भ है। यह संदर्भ Car.driverId होने से मॉडलिंग की जाएगी।

हाँ, यह सही तरीका है कि एक दूसरे को जोड़े।

अगर मैं डोमेन विशेषज्ञों से बात करूंगा, तो वे कभी भी इस तरह के संदर्भों की वैधता पर सवाल नहीं उठाएंगे

अपने डोमेन विशेषज्ञों से पूछने के लिए बिल्कुल सही सवाल नहीं है। यदि ड्राइवर मौजूद नहीं है, तो "व्यवसाय की लागत क्या है?"

मैं शायद DriverId की जाँच करने के लिए DriverRepository का उपयोग नहीं करूँगा। इसके बजाय, मैं इसे करने के लिए एक डोमेन सेवा का उपयोग करूंगा। मुझे लगता है कि यह आशय व्यक्त करने का बेहतर काम करता है - कवर के तहत, डोमेन सेवा अभी भी रिकॉर्ड की प्रणाली की जांच करती है।

तो कुछ ऐसा है

class DriverService {
    private final DriverRepository driverRepository;

    boolean doesDriverExist(DriverId driverId) {
        return driverRepository.exists(driverId);
    }
}

आप वास्तव में कई अलग-अलग बिंदुओं पर ड्राइवर के बारे में डोमेन को क्वेरी करते हैं

  • क्लाइंट से, कमांड भेजने से पहले
  • आवेदन में, मॉडल को कमांड पारित करने से पहले
  • डोमेन मॉडल के भीतर, कमांड प्रोसेसिंग के दौरान

इनमें से कोई भी या सभी चेक उपयोगकर्ता इनपुट में त्रुटियों को कम कर सकते हैं। लेकिन वे सभी बासी डेटा से काम कर रहे हैं; प्रश्न पूछने के तुरंत बाद अन्य समुच्चय बदल सकते हैं। इसलिए झूठी नकारात्मक / सकारात्मकता का हमेशा कुछ खतरा होता है।

  • एक अपवाद रिपोर्ट में, कमांड पूरा होने के बाद चलाएं

यहां, आप अभी भी बासी डेटा के साथ काम कर रहे हैं (जब आप रिपोर्ट चला रहे हैं तो एग्रेट्स कमांड चला सकते हैं, आप सभी एग्रीगेट्स को सबसे हाल के लेखन नहीं देख सकते हैं)। लेकिन समुच्चय के बीच की जाँच कभी भी सही नहीं होती है (Car.create (ड्राइवर: 7) उसी समय चल रही है जैसे Driver.delete (ड्राइवर: 7)) तो यह आपको जोखिम के विरुद्ध रक्षा की एक अतिरिक्त परत प्रदान करता है।


1
Driver.deleteमौजूद नहीं होना चाहिए। मैंने वास्तव में कभी ऐसा डोमेन नहीं देखा था जहाँ समुच्चय नष्ट हो जाते हैं। अपने आस-पास AR रखने से आप कभी भी अनाथों के साथ नहीं रह सकते।
प्लेक्स

1

यह पूछने में मदद मिल सकती है: क्या आप सुनिश्चित हैं कि कारों का निर्माण ड्राइवरों के साथ किया जाता है? मैंने कभी वास्तविक दुनिया में एक ड्राइवर से बनी कार के बारे में नहीं सुना है। यह प्रश्न क्यों महत्वपूर्ण है इसका कारण यह है कि यह आपको स्वतंत्र रूप से कार और ड्राइवर बनाने और फिर कुछ बाहरी तंत्र बनाने की दिशा में इशारा कर सकता है जो एक ड्राइवर को एक कार प्रदान करता है। एक कार बिना ड्राइवर संदर्भ के मौजूद हो सकती है और फिर भी एक वैध कार हो सकती है।

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


मैंने कार / ड्राइवर के संबंध के बारे में भी सोचा था - लेकिन एक DriverAssignment एग्रीगेट को शुरू करने से बस यह चलता है कि किस संदर्भ को मान्य करने की आवश्यकता है।
VoiceOfUnreason

1

लेकिन अब मैं सोच रहा हूँ कि बहुत ज्यादा नहीं है?

मुझे ऐसा लगता है। DB से दिए गए DriverId को लाना एक खाली सेट देता है यदि यह मौजूद नहीं है। इसलिए रिटर्न रिजल्ट चेक करने से यह पता चलता है कि क्या यह मौजूद है (और फिर प्राप्त करना) अनावश्यक है।

फिर वर्ग डिजाइन इसे अनावश्यक भी बनाता है

  • यदि कोई आवश्यकता है "एक खड़ी कार में ड्राइवर हो सकता है या नहीं"
  • यदि ड्राइवर ऑब्जेक्ट को DriverIdकंस्ट्रक्टर में ए और सेट की आवश्यकता होती है ।
  • यदि Carकेवल जरूरत है DriverId, एक Driver.Idगेट्टर है। कोई सेटर नहीं।

रिपोजिटरी व्यावसायिक नियमों के लिए जगह नहीं है

  • एक Carपरवाह अगर यह एक Driver(या उसकी आईडी कम से कम) है। एक Driverपरवाह है अगर यह एक है DriverIdRepositoryडेटा अखंडता के बारे में चिंताओं और चालक-रहित कारों के बारे में कम परवाह नहीं कर सका।
  • डीबी में डेटा अखंडता नियम होंगे। नॉन-न्यूल कीज़, नॉट-नल की कमी आदि। लेकिन डेटा अखंडता डेटा / टेबल स्कीमा के बारे में है, न कि व्यावसायिक नियमों के बारे में। इस मामले में हमारे बीच दृढ़ता से सहसंबद्ध, सहजीवन संबंध है लेकिन दोनों का मिश्रण नहीं है।
  • तथ्य यह है कि एक DriverIdव्यापार डोमेन बात है उचित वर्गों में नियंत्रित किया जाता है।

चिंता का उल्लंघन

... Repository.DriverIdExists()सवाल पूछने पर होता है ।

एक डोमेन ऑब्जेक्ट बनाएँ। नहीं एक हैं Driverतो शायद एक DriverInfo(सिर्फ एक DriverIdऔर Name, चलो कहते हैं) वस्तु। DriverIdनिर्माण पर मान्य है। यह मौजूद होना चाहिए, और सही प्रकार होना चाहिए, और जो भी हो। फिर यह एक क्लाइंट क्लास डिज़ाइन का मुद्दा है कि किसी गैर-मौजूद ड्राइवर / ड्राइवर से कैसे निपटें।

हो सकता है Carकि जब तक आप कॉल न करें, ड्राइवर के बिना ठीक है Car.Drive()। जिस स्थिति Carमें पाठ्यक्रम की वस्तु अपनी स्थिति सुनिश्चित करती है। बिना Driverअच्छी तरह से गाड़ी नहीं चला सकते , अभी तक नहीं।

किसी संपत्ति को उसके वर्ग से अलग करना बुरा है

ज़रूर, Car.DriverIdअगर आप चाहें। लेकिन यह कुछ इस तरह दिखना चाहिए:

public class Car {
    // Non-null driver has a driverId by definition/contract.
    protected DriverInfo myDriver;
    public DriverId {get { return myDriver.Id; }}

    public void Drive() {
       if (myDriver == null ) return errorMessage; // or something
       // ... continue driving
    }
}

यह नहीं:

public class Car {
    public int DriverId {get; protected set;}
}

अब Carसभी DriverIdवैधता मुद्दों से निपटना चाहिए - एक एकल जिम्मेदारी सिद्धांत उल्लंघन; और निरर्थक कोड शायद।

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