डेटा सत्यापन: अलग वर्ग या नहीं?


16

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

मेरा विशेष उदाहरण एक टूर्नामेंट और एक घटना / श्रेणी वर्ग पर विचार करता है: Tournamentऔर Event, जो एक खेल टूर्नामेंट का मॉडल बनाते हैं और प्रत्येक टूर्नामेंट में एक या कई श्रेणियां होती हैं।

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

कुछ ऐसे हिस्से भी हैं जिन्हें मुझे समग्र रूप से मान्य करने की आवश्यकता है, जैसे कि कक्षाएं एक-दूसरे के साथ कैसे एकीकृत होती हैं। उदाहरण के लिए, कैन की एकात्मक मान्यता Playerसिर्फ ठीक हो सकती है, लेकिन अगर किसी घटना में एक ही खिलाड़ी दो बार है, तो यह एक सत्यापन त्रुटि है।

तो इस बारे में कैसे ?: मैं अपने मॉडल वर्गों के बसने और डेटा जोड़ने के लिए इसी तरह के तरीकों का उपयोग करते समय बिल्कुल किसी भी पूर्व-जांच के बारे में भूल जाता हूं और इसके बजाय मैं सत्यापन कक्षाओं को संभालता हूं।

इसलिए हम कुछ ऐसा करना होगा EventValidatorएक साथ Eventएक सदस्य के रूप में, और एक validate()विधि है कि पूरी वस्तु की पुष्टि करता है, के साथ साथ विलक्षण तरीकों सभी सदस्यों के नियमों को मान्य करने के।

फिर, एक वैध वस्तु को तत्काल करने से पहले, मैं अवैध मूल्यों को रोकने के लिए मान्यता निष्पादित करूंगा।

क्या मेरा डिजाइन सही है? क्या मुझे कुछ अलग करना चाहिए?

इसके अलावा, क्या मुझे बूलियन रिटर्न सत्यापन विधि का उपयोग करना चाहिए? या सिर्फ एक अपवाद फेंक दें यदि सत्यापन विफल हो जाता है? ऐसा लगता है कि सबसे अच्छा विकल्प बूलियन वापसी के तरीके होंगे और उदाहरण के लिए, जब वस्तु को तत्काल किया जाता है, तो अपवाद को फेंक दें:

public Event() {
    EventValidator eventValidator = new EventValidator(this);
    if (!eventValidator.validate()) {
        // show error messages with methods defined in the validator
        throw new Exception(); // what type of exception would be best? should I create custom ones?
    }
}

जवाबों:


7

किसी तर्क को रचना के माध्यम से सौंपना ठीक है यदि वह तर्क किसी कार्यक्रम के निष्पादन के दौरान गतिशील रूप से बदलने वाला है। आपके द्वारा समझाए गए जटिल सत्यापन उतने ही अच्छे उम्मीदवार हैं जितने किसी रचना के माध्यम से किसी अन्य वर्ग को सौंप दिए जाते हैं।

याद रखें कि सत्यापन अलग-अलग क्षणों में हो सकते हैं।

आपके उदाहरण की तरह एक ठोस सत्यापनकर्ता को त्वरित करना एक बुरा विचार है क्योंकि यह आपके ईवेंट वर्ग को उस विशेष सत्यापनकर्ता को जोड़े देता है।

मान लेते हैं कि आप किसी DI ढांचे का उपयोग नहीं कर रहे हैं।

आप सत्यापनकर्ता को कंस्ट्रक्टर में जोड़ सकते हैं, या इसे सेटर विधि से इंजेक्ट कर सकते हैं। मैं सुझाव देता हूं कि एक कारखाने में एक निर्माता विधि घटना और सत्यापनकर्ता दोनों को तत्काल कर देती है और फिर इसे या तो घटना निर्माणकर्ता को या एक सेटवीडिएटर विधि के साथ पारित कर देती है।

जाहिर है एक वैलिडेटर इंटरफ़ेस और या अमूर्त वर्ग को रिटेन किया जाना चाहिए ताकि आपकी कक्षाएं इस पर निर्भर हों और किसी ठोस सत्यापनकर्ता पर नहीं।

कंस्ट्रक्टर में मान्य विधि को निष्पादित करना समस्याग्रस्त हो सकता है क्योंकि आप जिस राज्य को मान्य करना चाहते हैं वह सभी जगह अभी तक नहीं हो सकता है।

मेरा सुझाव है कि आप एक मान्य इंटरफ़ेस क्रेटा और अपनी कक्षाओं को इसे लागू करने दें, उस इंटरफ़ेस में एक मान्य () विधि हो सकती है।

इस तरह से आपके आवेदन के ऊपरी घटकों को वसीयत में विधि मान्य होती है (जो बदले में सत्यापनकर्ता सदस्य को सौंप दी जाती है)।

==> IValidable.java <==

import java.util.List;

public interface IValidable {
    public void setValidator(IValidator<Event> validator_);
    public void validate() throws ValidationException;
    public List<String> getMessages();
}

==> IValidator.java <==

import java.util.List;

public interface IValidator<T> {
    public boolean validate(T e);
    public List<String> getValidationMessages();
}

==> Event.java <==

import java.util.List;

public class Event implements IValidable {

    private IValidator<Event> validator;

    @Override
    public void setValidator(IValidator<Event> validator_) {
        this.validator = validator_;
    }

    @Override
    public void validate() throws ValidationException {
        if (!this.validator.validate(this)){
            throw new ValidationException("WTF!");
        }
    }

    @Override
    public List<String> getMessages() {
        return this.validator.getValidationMessages();
    }

}

==> SimpleEventValidator.java <==

import java.util.ArrayList;
import java.util.List;

public class SimpleEventValidator implements IValidator<Event> {

    private List<String> messages = new ArrayList<String>();
    @Override
    public boolean validate(Event e) {
        // do validations here, by accessing the public getters of e
        // propulate list of messages is necessary
        // this example always returns false    
        return false;
    }

    @Override
    public List<String> getValidationMessages() {
        return this.messages;
    }

}

==> मान्यकरण अपवाद। जावा <==

public class ValidationException extends Exception {
    public ValidationException(String message) {
        super(message);
    }

    private static final long serialVersionUID = 1L;
}

==> टेस्ट.जावा <==

public class Test {
    public static void main (String args[]){
        Event e = new Event();
        IValidator<Event> v = new SimpleEventValidator();
        e.setValidator(v);
        // set other thins to e like
        // e.setPlayers(player1,player2,player3)
        // e.setNumberOfMatches(3);
        // etc
        try {
            e.validate();
        } catch (ValidationException e1) {
            System.out.println("Your event doesn't comply with the federation regulations for the following reasons: ");
            for (String s: e.getMessages()){
                System.out.println(s);
            }
        }
    }
}

तो वर्ग पदानुक्रम के संदर्भ में यह जो मैंने सुझाया है, उससे बहुत भिन्न नहीं है? कंस्ट्रक्टर के अंदर सत्यापनकर्ता को तत्काल कॉल करने और कॉल करने के बजाय, इसे बनाया जाएगा और जब निष्पादन प्रवाह में आवश्यकता होगी, तो यह मुख्य अंतर है जिसे मैं देख सकता हूं।
dabadaba

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

अगर मैं किसी सूची या dictioary में त्रुटि संदेश को जोड़ने के लिए थे, उस में होना चाहिए Validatorया में Validable? और मैं इन संदेशों के संयोजन में कैसे काम कर सकता हूं ValidationException?
दाबाबा

1
@ डडबाबा सूची में आईवीडीलेटर कार्यान्वयनकर्ताओं का सदस्य होना चाहिए, लेकिन आईवीडबल को उस पद्धति तक पहुंच को जोड़ना चाहिए ताकि कार्यान्वयनकर्ता इसे प्रस्तुत कर सकें। मैंने मान लिया कि एक से अधिक सत्यापन संदेश वापस आ सकते हैं। पर CLIC संपादित n पहले मिनट नीचे दिए गए लिंक आप मतभेदों को देख सकते हैं। यदि आप साइड-बाय-साइड व्यू (कोई मार्कडाउन) का उपयोग करते हैं तो बेहतर है ।
ट्यूलेंस कोर्डोवा

3
संभवतः पांडित्यपूर्ण, लेकिन मुझे लगता Validatableहै कि यह एक बेहतर नाम है, Validableक्योंकि यह वास्तविक विशेषण है
user919426

4

मैं अपने मॉडल वर्गों के बसने और डेटा जोड़ने के समान तरीकों का उपयोग करते समय बिल्कुल किसी भी पूर्व-जांच के बारे में भूल जाता हूं

यही समस्या है। आदर्श रूप से आपको अपनी वस्तुओं को अमान्य स्थिति होने से रोकना चाहिए: अमान्य राज्य के साथ तात्कालिकता की अनुमति न दें और यदि आपके पास बसने और अन्य राज्य-परिवर्तन करने के तरीके हैं, तो एक अपवाद छोड़ दें।

इसके बजाय मैं सत्यापन वर्गों को सत्यापन को संभालने देता हूं।

यह विरोधाभासी नहीं है। यदि सत्यापन तर्क अपने स्वयं के वर्ग को वारंट करने के लिए पर्याप्त जटिल है, तो आप अभी भी सत्यापन को सौंप सकते हैं। और अगर मैं तुम्हें सही समझूं, तो ठीक यही तुम अभी कर रहे हो:

फिर, एक वैध वस्तु को तत्काल करने से पहले, मैं अवैध मूल्यों को रोकने के लिए मान्यता निष्पादित करूंगा।

यदि आपके पास अभी भी बसे हुए हैं, जिसके परिणामस्वरूप अमान्य स्थिति हो सकती है, तो वास्तव में बदलते राज्य से पहले मान्य करना सुनिश्चित करें । अन्यथा आपके पास एक त्रुटि संदेश होगा लेकिन फिर भी अपनी वस्तु को अमान्य स्थिति में छोड़ दें। फिर से: अपनी वस्तुओं को अमान्य स्थिति में आने से रोकें

इसके अलावा, क्या मुझे बूलियन रिटर्न सत्यापन विधि का उपयोग करना चाहिए? या सिर्फ एक अपवाद फेंक दें यदि सत्यापन विफल हो जाता है? मुझे लगता है कि सबसे अच्छा विकल्प बूलियन वापसी के तरीके होंगे और जब वस्तु को तत्काल किया जाता है तो अपवाद को फेंक दें

मेरे लिए अच्छा लगता है, क्योंकि सत्यापनकर्ता वैध या अमान्य इनपुट की अपेक्षा करता है, इसलिए उसके दृष्टिकोण से, अमान्य इनपुट अपवाद नहीं है।

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


क्या जाँच के बारे में तात्कालिकता और बसने में कोई जाँच नहीं है और एक अलग ऑपरेशन के रूप में मान्यता है? ट्यूलेंस कोर्डोवा जैसा कुछ सुझाव दिया। क्योंकि किसी सेटर या कंस्ट्रक्टर में अपवाद को मान्य करना और फेंकना उस सदस्य या ऑब्जेक्ट के लिए काम कर सकता है, लेकिन यह जाँचने में मदद नहीं करता है कि क्या सिस्टम पूरी तरह से ठीक है।
दादाबा

@ दाबाबा मेरा जवाब एक टिप्पणी के लिए लंबे समय तक था, कृपया ऊपर अद्यतन देखें
फेबियन शेंगलर

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

3
अपरिवर्तनीय वस्तुओं को बनाने के लिए, सभी सेटर्स को हटा दें और मूल्यों को सेट करने के लिए केवल कंस्ट्रक्टर का उपयोग करें। यदि आपके पास वैकल्पिक डेटा या डेटा है जो एक बार में उपलब्ध नहीं है, तो बिल्डर पैटर्न का उपयोग करने पर विचार करें: developer.amd.com/community/blog/2009/02/02/06/…
Fabian Schmengler
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.