वर्ग हे ऍप्लिकेशनचे बिल्डिंग ब्लॉक्स आहेत. इमारतीत जशी विटा. खराब लिखित वर्ग अखेरीस समस्या निर्माण करू शकतात. वर्ग योग्यरित्या लिहिलेला आहे की नाही हे समजून घेण्यासाठी, तुम्ही ते "गुणवत्ता मानके" पर्यंत कसे मोजते ते तपासू शकता. Java मध्ये, ही तथाकथित SOLID तत्त्वे आहेत आणि आम्ही त्यांच्याबद्दल बोलणार आहोत.
जावा मध्ये ठोस तत्त्वे
SOLID हे ओओपी आणि क्लास डिझाइनच्या पहिल्या पाच तत्त्वांच्या कॅपिटल अक्षरांपासून तयार केलेले संक्षिप्त रूप आहे. तत्त्वे रॉबर्ट मार्टिन यांनी 2000 च्या दशकाच्या सुरुवातीस व्यक्त केली होती आणि नंतर संक्षेप मायकेल फेदर्सने सादर केले. येथे ठोस तत्त्वे आहेत:- एकल जबाबदारी तत्त्व
- बंद तत्त्व उघडा
- लिस्कोव्ह प्रतिस्थापन तत्त्व
- इंटरफेस पृथक्करण तत्त्व
- अवलंबित्व उलटे तत्त्व
सिंगल रिस्पॉन्सिबिलिटी प्रिन्सिपल (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);
}
}
}
ओपन क्लोज्ड प्रिन्सिपल (ओसीपी)
हे तत्त्व खालीलप्रमाणे वर्णन केले आहे: सॉफ्टवेअर संस्था (वर्ग, मॉड्यूल, फंक्शन्स इ.) विस्तारासाठी खुल्या असाव्यात, परंतु सुधारणेसाठी बंद केल्या पाहिजेत . याचा अर्थ वर्गाच्या विद्यमान कोडमध्ये बदल न करता वर्गाचे बाह्य वर्तन बदलणे शक्य असावे. या तत्त्वानुसार, वर्गांची रचना केली जाते जेणेकरून विशिष्ट परिस्थितींमध्ये फिट होण्यासाठी वर्ग बदलण्यासाठी तो वाढवणे आणि काही फंक्शन्स ओव्हरराइड करणे आवश्यक आहे. याचा अर्थ प्रणाली लवचिक असणे आवश्यक आहे, स्त्रोत कोड न बदलता बदलत्या परिस्थितीत कार्य करण्यास सक्षम असणे आवश्यक आहे. ऑर्डर प्रक्रियेचा समावेश असलेले आमचे उदाहरण पुढे चालू ठेवत, समजा ऑर्डरवर प्रक्रिया करण्यापूर्वी तसेच पुष्टीकरण ईमेल पाठवल्यानंतर आम्हाला काही क्रिया करणे आवश्यक आहे. बदलण्याऐवजी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()
. आता क्लायंटला हा इंटरफेस वापरायचा आहे, परंतु केवळ पीडीएफ स्वरूपात अहवाल वापरायचा आहे, Excel मध्ये नाही. ही कार्यक्षमता या क्लायंटला संतुष्ट करेल का? नाही. क्लायंटला दोन पद्धती अंमलात आणाव्या लागतील, त्यापैकी एका पद्धतीची मोठ्या प्रमाणावर आवश्यकता नाही आणि ती अस्तित्वात आहे ती केवळ अॅलेक्सचे आभार मानते, ज्याने सॉफ्टवेअर डिझाइन केले आहे. क्लायंट एकतर भिन्न इंटरफेस वापरेल किंवा Excel अहवालासाठी पद्धतीसह काहीही करणार नाही. मग यावर उपाय काय? हे विद्यमान इंटरफेस दोन लहान मध्ये विभाजित करणे आहे. एक पीडीएफ अहवालांसाठी, दुसरा एक्सेल अहवालांसाठी. हे क्लायंटला फक्त त्यांना आवश्यक असलेली कार्यक्षमता वापरू देते.
अवलंबित्व उलथापालथ तत्त्व (DIP)
जावामध्ये, या सॉलिड तत्त्वाचे खालीलप्रमाणे वर्णन केले आहे: सिस्टममधील अवलंबित्व अमूर्ततेवर आधारित आहे. उच्च-स्तरीय मॉड्यूल निम्न-स्तरीय मॉड्यूलवर अवलंबून नाहीत. अॅब्स्ट्रॅक्शन तपशीलांवर अवलंबून नसावेत. तपशील अमूर्ततेवर अवलंबून असले पाहिजेत. सॉफ्टवेअर डिझाइन केले जाणे आवश्यक आहे जेणेकरून विविध मॉड्यूल स्वयं-समाविष्ट असतील आणि अॅब्स्ट्रॅक्शनद्वारे एकमेकांशी जोडले जातील. या तत्त्वाचा उत्कृष्ट वापर म्हणजे स्प्रिंग फ्रेमवर्क. स्प्रिंग फ्रेमवर्कमध्ये, सर्व मॉड्यूल स्वतंत्र घटक म्हणून लागू केले जातात जे एकत्र कार्य करू शकतात. ते इतके स्वायत्त आहेत की ते स्प्रिंग फ्रेमवर्क व्यतिरिक्त इतर प्रोग्राम मॉड्यूल्समध्ये सहजपणे वापरले जाऊ शकतात. हे बंद आणि खुल्या तत्त्वांच्या अवलंबनामुळे प्राप्त झाले आहे. सर्व मॉड्यूल्स फक्त अॅबस्ट्रॅक्शनमध्ये प्रवेश देतात, जे दुसर्या मॉड्यूलमध्ये वापरले जाऊ शकतात. एक उदाहरण वापरून हे स्पष्ट करण्याचा प्रयत्न करूया. एकल जबाबदारीच्या तत्त्वाबद्दल बोलताना, आम्ही विचार केला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 प्रोग्रामिंगच्या मूलभूत गोष्टींबद्दल अधिक जाणून घ्याल — काहीही कंटाळवाणे नाही आणि शेकडो तासांचा सराव —. काही कार्ये सोडवण्याची वेळ आली आहे :)
GO TO FULL VERSION