CodeGym/Java Blog/अनियमित/SOLID: जावा में क्लास डिजाइन के पांच बुनियादी सिद्धांत
John Squirrels
स्तर 41
San Francisco

SOLID: जावा में क्लास डिजाइन के पांच बुनियादी सिद्धांत

अनियमित ग्रुप में प्रकाशित
सदस्य
कक्षाएं अनुप्रयोगों के निर्माण खंड हैं। जैसे किसी भवन में ईंटें। खराब लिखित कक्षाएं अंततः समस्याएँ पैदा कर सकती हैं। SOLID: Java में क्लास डिज़ाइन के पाँच बुनियादी सिद्धांत - 1यह समझने के लिए कि क्या कक्षा सही ढंग से लिखी गई है, आप जांच सकते हैं कि यह "गुणवत्ता मानकों" तक कैसे मापता है। जावा में, ये तथाकथित ठोस सिद्धांत हैं, और हम उनके बारे में बात करने जा रहे हैं।

जावा में ठोस सिद्धांत

SOLID OOP और क्लास डिज़ाइन के पहले पाँच सिद्धांतों के बड़े अक्षरों से बना एक संक्षिप्त नाम है। 2000 के दशक की शुरुआत में सिद्धांतों को रॉबर्ट मार्टिन द्वारा व्यक्त किया गया था, और फिर बाद में माइकल फेदर्स द्वारा संक्षिप्त नाम पेश किया गया था। यहाँ ठोस सिद्धांत हैं:
  1. एकल उत्तरदायित्व सिद्धांत
  2. खुला बंद सिद्धांत
  3. लिस्कोव प्रतिस्थापन सिद्धांत
  4. इंटरफ़ेस पृथक्करण सिद्धांत
  5. निर्भरता उलटा सिद्धांत

एकल उत्तरदायित्व सिद्धांत (SRP)

यह सिद्धांत बताता है कि किसी वर्ग को बदलने के लिए कभी भी एक से अधिक कारण नहीं होने चाहिए। प्रत्येक वस्तु की एक जिम्मेदारी होती है, जो पूरी तरह से कक्षा में समाहित होती है। कक्षा की सभी सेवाओं का उद्देश्य इस उत्तरदायित्व का समर्थन करना है। यदि आवश्यक हो तो ऐसी कक्षाओं को हमेशा संशोधित करना आसान होगा, क्योंकि यह स्पष्ट है कि वर्ग क्या है और इसके लिए ज़िम्मेदार नहीं है। दूसरे शब्दों में, हम परिवर्तन करने में सक्षम होंगे और परिणामों से नहीं डरेंगे, अर्थात अन्य वस्तुओं पर प्रभाव। इसके अतिरिक्त, इस तरह के कोड का परीक्षण करना बहुत आसान है, क्योंकि आपके परीक्षण अन्य सभी से अलगाव में कार्यक्षमता के एक टुकड़े को कवर कर रहे हैं। एक मॉड्यूल की कल्पना करें जो ऑर्डर को प्रोसेस करता है। यदि कोई आदेश सही ढंग से बनता है, तो यह मॉड्यूल इसे डेटाबेस में सहेजता है और आदेश की पुष्टि करने के लिए एक ईमेल भेजता है:
public class OrderProcessor {

    public void process(Order order){
        if (order.isValid() && save(order)) {
            sendConfirmationEmail(order);
        }
    }

    private boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }

    private void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
यह मॉड्यूल तीन कारणों से बदल सकता है। सबसे पहले, प्रसंस्करण आदेश के लिए तर्क बदल सकता है। दूसरा, जिस तरह से ऑर्डर सहेजे जाते हैं (डेटाबेस प्रकार) बदल सकते हैं। तीसरा, पुष्टिकरण भेजने का तरीका बदल सकता है (उदाहरण के लिए, मान लें कि हमें ईमेल के बजाय पाठ संदेश भेजने की आवश्यकता है)। एकल उत्तरदायित्व सिद्धांत का तात्पर्य है कि इस समस्या के तीन पहलू वास्तव में तीन अलग-अलग उत्तरदायित्व हैं। इसका मतलब है कि वे अलग-अलग वर्गों या मॉड्यूल में होने चाहिए। कई संस्थाओं का संयोजन जो अलग-अलग समय पर और अलग-अलग कारणों से बदल सकते हैं, एक खराब डिजाइन निर्णय माना जाता है। मॉड्यूल को तीन अलग-अलग मॉड्यूल में विभाजित करना बेहतर होता है, जिनमें से प्रत्येक एक ही कार्य करता है:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}

public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}

खुला बंद सिद्धांत (OCP)

इस सिद्धांत को निम्नानुसार वर्णित किया गया है: सॉफ्टवेयर इकाइयां (वर्ग, मॉड्यूल, कार्य, आदि) विस्तार के लिए खुली होनी चाहिए, लेकिन संशोधन के लिए बंद होनी चाहिए । इसका मतलब यह है कि कक्षा के मौजूदा कोड में बदलाव किए बिना कक्षा के बाहरी व्यवहार को बदलना संभव होना चाहिए। इस सिद्धांत के अनुसार, कक्षाओं को इस तरह से डिज़ाइन किया गया है कि किसी वर्ग को विशिष्ट परिस्थितियों में फिट करने के लिए केवल इसे विस्तारित करने और कुछ कार्यों को ओवरराइड करने की आवश्यकता होती है। इसका मतलब यह है कि सिस्टम लचीला होना चाहिए, स्रोत कोड को बदले बिना बदलती परिस्थितियों में काम करने में सक्षम होना चाहिए। ऑर्डर प्रोसेसिंग से जुड़े हमारे उदाहरण को जारी रखते हुए, मान लीजिए कि ऑर्डर संसाधित होने से पहले और साथ ही पुष्टिकरण ईमेल भेजे जाने के बाद हमें कुछ क्रियाएं करने की आवश्यकता है। बदलने के बजायOrderProcessorवर्ग ही, हम खुले बंद सिद्धांत का उल्लंघन किए बिना अपने उद्देश्य को पूरा करने के लिए इसका विस्तार करेंगे:
public class OrderProcessorWithPreAndPostProcessing extends OrderProcessor {

    @Override
    public void process(Order order) {
        beforeProcessing();
        super.process(order);
        afterProcessing();
    }

    private void beforeProcessing() {
        // Take some action before processing the order
    }

    private void afterProcessing() {
        // Take some action after processing the order
    }
}

लिस्कोव प्रतिस्थापन सिद्धांत (LSP)

यह खुला बंद सिद्धांत का एक रूपांतर है जिसका हमने पहले उल्लेख किया था। इसे निम्नानुसार परिभाषित किया जा सकता है: प्रोग्राम के गुणों को बदले बिना वस्तुओं को उपवर्गों की वस्तुओं द्वारा प्रतिस्थापित किया जा सकता है। इसका मतलब यह है कि बेस क्लास का विस्तार करके बनाई गई कक्षा को इसके तरीकों को ओवरराइड करना चाहिए ताकि ग्राहक के दृष्टिकोण से कार्यक्षमता से समझौता न हो। अर्थात्, यदि कोई डेवलपर आपकी कक्षा का विस्तार करता है और किसी एप्लिकेशन में इसका उपयोग करता है, तो उसे किसी भी ओवरराइड विधियों के अपेक्षित व्यवहार को नहीं बदलना चाहिए। उपवर्गों को बेस क्लास के तरीकों को ओवरराइड करना चाहिए ताकि क्लाइंट के दृष्टिकोण से कार्यक्षमता टूट न जाए। हम इसे निम्नलिखित उदाहरण में विस्तार से देख सकते हैं। मान लीजिए कि हमारे पास एक वर्ग है जो ऑर्डर को मान्य करने के लिए ज़िम्मेदार है और यह जांचता है कि ऑर्डर में सभी सामान स्टॉक में हैं या नहीं।isValid()विधि जो सही या गलत लौटाती है :
public class OrderStockValidator {

    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if (!item.isInStock()) {
                return false;
            }
        }

        return true;
    }
}
यह भी मान लें कि कुछ ऑर्डर को अन्य की तुलना में अलग तरह से मान्य करने की आवश्यकता है, उदाहरण के लिए कुछ ऑर्डर के लिए हमें यह जांचने की आवश्यकता है कि क्या ऑर्डर में सभी सामान स्टॉक में हैं और क्या सभी सामान पैक किए गए हैं। ऐसा करने के लिए, हम OrderStockValidatorक्लास बनाकर क्लास का विस्तार करते हैं OrderStockAndPackValidator:
public class OrderStockAndPackValidator extends OrderStockValidator {

    @Override
    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if ( !item.isInStock() || !item.isPacked() ){
                throw new IllegalStateException(
                     String.format("Order %d is not valid!", order.getId())
                );
            }
        }

        return true;
    }
}
लेकिन यहां हमने लिस्कोव प्रतिस्थापन सिद्धांत का उल्लंघन किया है, क्योंकि यदि आदेश सत्यापन विफल हो जाता है, तो झूठीIllegalStateException वापसी के बजाय, हमारी विधि एक फेंकता है । इस कोड का उपयोग करने वाले ग्राहक इसकी अपेक्षा नहीं करते हैं: वे सही या गलत के वापसी मूल्य की अपेक्षा करते हैं । इससे रनटाइम त्रुटियां हो सकती हैं।

इंटरफ़ेस पृथक्करण सिद्धांत (ISP)

यह सिद्धांत निम्नलिखित कथन की विशेषता है: ग्राहक को उन तरीकों को लागू करने के लिए मजबूर नहीं किया जाना चाहिए जिनका वे उपयोग नहीं करेंगे । इंटरफ़ेस पृथक्करण सिद्धांत का अर्थ है कि इंटरफ़ेस जो "मोटे" हैं, उन्हें छोटे, अधिक विशिष्ट में विभाजित किया जाना चाहिए, ताकि छोटे इंटरफ़ेस का उपयोग करने वाले ग्राहक केवल उन तरीकों के बारे में जान सकें जो उन्हें अपने काम के लिए चाहिए। नतीजतन, जब एक इंटरफ़ेस विधि बदलती है, तो उस विधि का उपयोग नहीं करने वाले किसी भी क्लाइंट को नहीं बदलना चाहिए। इस उदाहरण पर विचार करें: एलेक्स, एक डेवलपर, ने एक "रिपोर्ट" इंटरफ़ेस बनाया है और दो तरीके जोड़े हैं: generateExcel()औरgeneratedPdf(). अब क्लाइंट इस इंटरफ़ेस का उपयोग करना चाहता है, लेकिन केवल पीडीएफ प्रारूप में रिपोर्ट का उपयोग करना चाहता है, एक्सेल में नहीं। क्या यह कार्यक्षमता इस क्लाइंट को संतुष्ट करेगी? नहीं। ग्राहक को दो तरीकों को लागू करना होगा, जिनमें से एक की काफी हद तक जरूरत नहीं है और यह केवल एलेक्स के लिए धन्यवाद है, जिसने सॉफ्टवेयर डिजाइन किया था। क्लाइंट या तो एक अलग इंटरफ़ेस का उपयोग करेगा या एक्सेल रिपोर्ट के लिए विधि के साथ कुछ नहीं करेगा। तो उपाय क्या है? यह मौजूदा इंटरफ़ेस को दो छोटे में विभाजित करना है। एक पीडीएफ रिपोर्ट के लिए, दूसरा एक्सेल रिपोर्ट के लिए। यह ग्राहकों को केवल उनकी जरूरत की कार्यक्षमता का उपयोग करने देता है।

निर्भरता उलटा सिद्धांत (डीआईपी)

जावा में, इस ठोस सिद्धांत को इस प्रकार वर्णित किया गया है: सिस्टम के भीतर निर्भरता अमूर्तता पर आधारित होती है. उच्च-स्तरीय मॉड्यूल निचले-स्तर के मॉड्यूल पर निर्भर नहीं होते हैं। सार विवरण पर निर्भर नहीं होना चाहिए। विवरण सार पर निर्भर होना चाहिए। सॉफ्टवेयर को डिजाइन करने की जरूरत है ताकि विभिन्न मॉड्यूल स्व-निहित हों और अमूर्तता के माध्यम से एक दूसरे से जुड़े हों। इस सिद्धांत का एक उत्कृष्ट अनुप्रयोग स्प्रिंग फ्रेमवर्क है। स्प्रिंग फ्रेमवर्क में, सभी मॉड्यूल अलग-अलग घटकों के रूप में कार्यान्वित किए जाते हैं जो एक साथ काम कर सकते हैं। वे इतने स्वायत्त हैं कि उनका उपयोग स्प्रिंग फ्रेमवर्क के अलावा अन्य प्रोग्राम मॉड्यूल में भी आसानी से किया जा सकता है। यह बंद और खुले सिद्धांतों की निर्भरता के कारण हासिल किया जाता है। सभी मॉड्यूल केवल अमूर्तता तक पहुंच प्रदान करते हैं, जिसका उपयोग दूसरे मॉड्यूल में किया जा सकता है। आइए एक उदाहरण का उपयोग करके इसे स्पष्ट करने का प्रयास करें। एकल उत्तरदायित्व सिद्धांत की बात करते हुए, हमने विचार कियाOrderProcessorकक्षा। आइए इस वर्ग के कोड पर एक और नज़र डालें:
public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}
इस उदाहरण में, हमारी OrderProcessorकक्षा दो विशिष्ट वर्गों पर निर्भर करती है: MySQLOrderRepositoryऔर ConfirmationEmailSender। हम इन वर्गों का कोड भी प्रस्तुत करेंगे:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
ये वर्ग उस चीज़ से बहुत दूर हैं जिसे हम अमूर्त कहते हैं। और डिपेंडेंसी व्युत्क्रम सिद्धांत के दृष्टिकोण से, विशिष्ट कार्यान्वयन के बजाय, कुछ सार बनाकर शुरू करना बेहतर होगा, जिसके साथ हम भविष्य में काम कर सकते हैं। आइए दो इंटरफेस बनाएं: MailSenderऔर OrderRepository)। ये हमारे सार होंगे:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
अब हम इन इंटरफेस को उन कक्षाओं में लागू करते हैं जो इसके लिए पहले से ही तैयार हैं:
public class ConfirmationEmailSender implements MailSender {

    @Override
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }

}

public class MySQLOrderRepository implements OrderRepository {

    @Override
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}
हमने प्रारंभिक कार्य किया ताकि हमारी OrderProcessorकक्षा ठोस विवरणों पर नहीं, बल्कि अमूर्तता पर निर्भर हो। हम क्लास कंस्ट्रक्टर में अपनी निर्भरता जोड़कर इसे बदल देंगे:
public class OrderProcessor {

    private MailSender mailSender;
    private OrderRepository repository;

    public OrderProcessor(MailSender mailSender, OrderRepository repository) {
        this.mailSender = mailSender;
        this.repository = repository;
    }

    public void process(Order order){
        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }
}
अब हमारी कक्षा सार पर निर्भर करती है, विशिष्ट कार्यान्वयन पर नहीं। OrderProcessorकिसी वस्तु के निर्माण के समय वांछित निर्भरता को जोड़कर हम उसके व्यवहार को आसानी से बदल सकते हैं। हमने जावा में ठोस डिजाइन सिद्धांतों की जांच की है। CodeGym पाठ्यक्रम में आप सामान्य रूप से OOP के बारे में और Java प्रोग्रामिंग की मूल बातें — कुछ भी उबाऊ नहीं और सैकड़ों घंटे अभ्यास — सीखेंगे। कुछ कार्यों को हल करने का समय :)
टिप्पणियां
  • लोकप्रिय
  • नया
  • पुराना
टिप्पणी लिखने के लिए आपको साइन इन करना होगा
इस पेज पर अभी तक कोई टिप्पणियां नहीं हैं