समस्येबद्दल अधिक
प्रथम, आम्ही जुन्या प्रणालीच्या वर्तनाचे अनुकरण करू. समजा ते कामावर किंवा शाळेत उशीर झाल्याची सबब निर्माण करते. हे करण्यासाठी, त्यात एकExcuse
इंटरफेस आहे ज्यामध्ये generateExcuse()
, likeExcuse()
आणि dislikeExcuse()
पद्धती आहेत.
public interface Excuse {
String generateExcuse();
void likeExcuse(String excuse);
void dislikeExcuse(String excuse);
}
वर्ग WorkExcuse
हा इंटरफेस लागू करतो:
public class WorkExcuse implements Excuse {
private String[] excuses = {"in an incredible confluence of circumstances, I ran out of hot water and had to wait until sunlight, focused using a magnifying glass, heated a mug of water so that I could wash.",
"the artificial intelligence in my alarm clock failed me, waking me up an hour earlier than normal. Because it is winter, I thought it was still nighttime and I fell back asleep. Everything after that is a bit hazy.",
"my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia."};
private String [] apologies = {"This will not happen again, of course. I'm very sorry.", "I apologize for my unprofessional behavior.", "There is no excuse for my actions. I am not worthy of this position."};
@Override
public String generateExcuse() { // Randomly select an excuse from the array
String result = "I was late today because " + excuses[(int) Math.round(Math.random() + 1)] + "\\n" +
apologies[(int) Math.round(Math.random() + 1)];
return result;
}
@Override
public void likeExcuse(String excuse) {
// Duplicate the element in the array so that its chances of being chosen are higher
}
@Override
public void dislikeExcuse(String excuse) {
// Remove the item from the array
}
}
चला आमच्या उदाहरणाची चाचणी घेऊ:
Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
आउटपुट:
"I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
I apologize for my unprofessional behavior.
आता कल्पना करा की तुम्ही निमित्त निर्माण करणारी सेवा सुरू केली आहे, आकडेवारी गोळा केली आहे आणि तुमच्या लक्षात आले आहे की तुमचे बहुतेक वापरकर्ते विद्यापीठाचे विद्यार्थी आहेत. या गटाला अधिक चांगल्या प्रकारे सेवा देण्यासाठी, तुम्ही दुसर्या विकसकाला एक प्रणाली तयार करण्यास सांगितले जी विशेषतः विद्यापीठातील विद्यार्थ्यांसाठी निमित्त निर्माण करते. डेव्हलपमेंट टीमने मार्केट रिसर्च केले, सबब रँक केले, काही आर्टिफिशियल इंटेलिजन्स जोडले आणि ट्रॅफिक रिपोर्ट्स, हवामान अहवाल इत्यादींसह सेवा एकत्रित केली. आता तुमच्याकडे युनिव्हर्सिटी विद्यार्थ्यांसाठी निमित्त निर्माण करण्यासाठी लायब्ररी आहे, परंतु त्याचा इंटरफेस वेगळा आहे: StudentExcuse
.
public interface StudentExcuse {
String generateExcuse();
void dislikeExcuse(String excuse);
}
या इंटरफेसमध्ये दोन पद्धती आहेत: generateExcuse
, जे निमित्त निर्माण करते आणि dislikeExcuse
, जे निमित्त भविष्यात पुन्हा दिसण्यापासून प्रतिबंधित करते. तृतीय-पक्ष लायब्ररी संपादित केली जाऊ शकत नाही, म्हणजे तुम्ही त्याचा स्त्रोत कोड बदलू शकत नाही. आमच्याकडे आता इंटरफेसची अंमलबजावणी करणारी दोन वर्ग असलेली प्रणाली आणि इंटरफेस लागू करणारी वर्ग Excuse
असलेली लायब्ररी आहे : SuperStudentExcuse
StudentExcuse
public class SuperStudentExcuse implements StudentExcuse {
@Override
public String generateExcuse() {
// Logic for the new functionality
return "An incredible excuse adapted to the current weather conditions, traffic jams, or delays in public transport schedules.";
}
@Override
public void dislikeExcuse(String excuse) {
// Adds the reason to a blacklist
}
}
कोड बदलता येत नाही. वर्तमान वर्ग पदानुक्रम असे दिसते: सिस्टमची ही आवृत्ती फक्त एक्सक्यूज इंटरफेससह कार्य करते. तुम्ही कोड पुन्हा लिहू शकत नाही: मोठ्या ऍप्लिकेशनमध्ये, असे बदल करणे ही एक लांबलचक प्रक्रिया बनू शकते किंवा ऍप्लिकेशनचे तर्क मोडू शकते. आम्ही बेस इंटरफेस सादर करू शकतो आणि पदानुक्रम वाढवू शकतो: हे करण्यासाठी, आम्हाला Excuse
इंटरफेसचे नाव बदलावे लागेल. परंतु गंभीर ऍप्लिकेशन्समध्ये अतिरिक्त पदानुक्रम अवांछित आहे: सामान्य मूळ घटक सादर केल्याने आर्किटेक्चर खंडित होते. तुम्ही एक इंटरमीडिएट क्लास अंमलात आणला पाहिजे जो आम्हाला कमीत कमी नुकसानासह नवीन आणि जुनी दोन्ही कार्यक्षमता वापरू देईल. थोडक्यात, आपल्याला अॅडॉप्टरची आवश्यकता आहे .
अडॅप्टर पॅटर्नमागील तत्त्व
अॅडॉप्टर ही एक इंटरमीडिएट ऑब्जेक्ट आहे जी एका ऑब्जेक्टचे मेथड कॉल्स दुसऱ्या ऑब्जेक्टला समजू देते. चला आमच्या उदाहरणासाठी अॅडॉप्टर लागू करू आणि त्याला कॉल करूMiddleware
. आमच्या अॅडॉप्टरने एका ऑब्जेक्टशी सुसंगत इंटरफेस लागू करणे आवश्यक आहे. ते होऊ दे Excuse
. हे Middleware
पहिल्या ऑब्जेक्टच्या पद्धतींना कॉल करण्यास अनुमती देते. Middleware
कॉल प्राप्त करतो आणि दुसर्या ऑब्जेक्टवर सुसंगत मार्गाने अग्रेषित करतो. येथे आणि Middleware
पद्धतींसह अंमलबजावणी आहे : generateExcuse
dislikeExcuse
public class Middleware implements Excuse { // 1. Middleware becomes compatible with WorkExcuse objects via the Excuse interface
private StudentExcuse superStudentExcuse;
public Middleware(StudentExcuse excuse) { // 2. Get a reference to the object being adapted
this.superStudentExcuse = excuse;
}
@Override
public String generateExcuse() {
return superStudentExcuse.generateExcuse(); // 3. The adapter implements an interface method
}
@Override
public void dislikeExcuse(String excuse) {
// The method first adds the excuse to the blacklist,
// Then passes it to the dislikeExcuse method of the superStudentExcuse object.
}
// The likeExcuse method will appear later
}
चाचणी (क्लायंट कोडमध्ये):
public class Test {
public static void main(String[] args) {
Excuse excuse = new WorkExcuse(); // We create objects of the classes
StudentExcuse newExcuse = new SuperStudentExcuse(); // that must be compatible.
System.out.println("An ordinary excuse for an employee:");
System.out.println(excuse.generateExcuse());
System.out.println("\n");
Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Wrap the new functionality in the adapter object
System.out.println("Using new functionality with the adapter:");
System.out.println(adaptedStudentExcuse.generateExcuse()); // The adapter calls the adapted method
}
}
आउटपुट:
An ordinary excuse for an employee:
I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
There is no excuse for my actions. I am not worthy of this position.
Using new functionality with the adapter:
सद्य हवामान परिस्थिती, ट्रॅफिक जाम किंवा सार्वजनिक वाहतुकीच्या वेळापत्रकातील विलंब यांच्याशी जुळवून घेतलेले एक अविश्वसनीय निमित्त. कोणत्याही अतिरिक्त बदलांशिवाय ही generateExcuse
पद्धत फक्त दुसर्या ऑब्जेक्टवर कॉल पास करते. या dislikeExcuse
पद्धतीमुळे आम्हाला प्रथम काळ्या यादीत टाकणे आवश्यक होते. इंटरमीडिएट डेटा प्रोसेसिंग करण्याची क्षमता लोकांना अडॅप्टर पॅटर्न आवडते याचे एक कारण आहे. पण त्या पद्धतीचे काय likeExcuse
, जी इंटरफेसचा भाग आहे Excuse
पण इंटरफेसचा भाग नाही StudentExcuse
? नवीन कार्यक्षमता या ऑपरेशनला समर्थन देत नाही. UnsupportedOperationException
या परिस्थितीसाठी शोध लावला गेला . विनंती केलेले ऑपरेशन समर्थित नसल्यास ते फेकले जाते. चला वापरुया. Middleware
वर्गाची नवीन अंमलबजावणी कशी दिसते:
public class Middleware implements Excuse {
private StudentExcuse superStudentExcuse;
public Middleware(StudentExcuse excuse) {
this.superStudentExcuse = excuse;
}
@Override
public String generateExcuse() {
return superStudentExcuse.generateExcuse();
}
@Override
public void likeExcuse(String excuse) {
throw new UnsupportedOperationException("The likeExcuse method is not supported by the new functionality");
}
@Override
public void dislikeExcuse(String excuse) {
// The method accesses a database to fetch additional information,
// and then passes it to the superStudentExcuse object's dislikeExcuse method.
}
}
पहिल्या दृष्टीक्षेपात, हे समाधान फार चांगले वाटत नाही, परंतु कार्यक्षमतेचे अनुकरण केल्याने परिस्थिती गुंतागुंत होऊ शकते. जर क्लायंटने लक्ष दिले आणि अॅडॉप्टर चांगले दस्तऐवजीकरण केले असेल तर असे समाधान स्वीकार्य आहे.
अॅडॉप्टर कधी वापरायचे
-
जेव्हा आपल्याला तृतीय-पक्ष वर्ग वापरण्याची आवश्यकता असते, परंतु त्याचा इंटरफेस मुख्य अनुप्रयोगाशी विसंगत असतो. लक्ष्य ऑब्जेक्ट समजू शकणार्या फॉरमॅटमध्ये कॉल्स गुंडाळणारे अॅडॉप्टर ऑब्जेक्ट कसे तयार करायचे हे वरील उदाहरण दाखवते.
-
जेव्हा अनेक विद्यमान उपवर्गांना काही सामान्य कार्यक्षमतेची आवश्यकता असते. अतिरिक्त उपवर्ग तयार करण्याऐवजी (ज्यामुळे कोडची डुप्लिकेशन होईल), अॅडॉप्टर वापरणे चांगले.
फायदे आणि तोटे
फायदा: अॅडॉप्टर क्लायंटकडून एका ऑब्जेक्टवरून दुसऱ्या ऑब्जेक्टवर प्रक्रिया करण्याच्या विनंत्यांची माहिती लपवते. क्लायंट कोड डेटाचे स्वरूपन किंवा लक्ष्य पद्धतीवर कॉल हाताळण्याचा विचार करत नाही. हे खूप क्लिष्ट आहे, आणि प्रोग्रामर आळशी आहेत :) गैरसोय: प्रकल्पाचा कोड बेस अतिरिक्त वर्गांद्वारे क्लिष्ट आहे. तुमच्याकडे बरेच विसंगत इंटरफेस असल्यास, अतिरिक्त वर्गांची संख्या नियंत्रणात ठेवता येत नाही.अॅडॉप्टरला दर्शनी भाग किंवा डेकोरेटरसह गोंधळात टाकू नका
केवळ वरवरच्या तपासणीसह, अॅडॉप्टरचा दर्शनी भाग आणि सजावटीच्या नमुन्यांसह गोंधळ होऊ शकतो. अॅडॉप्टर आणि दर्शनी भागात फरक असा आहे की दर्शनी भाग नवीन इंटरफेस सादर करतो आणि संपूर्ण उपप्रणाली गुंडाळतो. आणि डेकोरेटर, अॅडॉप्टरच्या विपरीत, इंटरफेसऐवजी ऑब्जेक्ट स्वतः बदलतो.चरण-दर-चरण अल्गोरिदम
-
प्रथम, तुमच्याकडे एक समस्या आहे याची खात्री करा की हा नमुना सोडवू शकतो.
-
क्लायंट इंटरफेस परिभाषित करा जो अप्रत्यक्षपणे विसंगत वस्तूंशी संवाद साधण्यासाठी वापरला जाईल.
-
अॅडॉप्टर क्लासला मागील चरणात परिभाषित इंटरफेस इनहेरिट करा.
-
अडॅप्टर क्लासमध्ये, अॅडप्टी ऑब्जेक्टचा संदर्भ साठवण्यासाठी फील्ड तयार करा. हा संदर्भ कन्स्ट्रक्टरला दिला जातो.
-
अडॅप्टरमधील सर्व क्लायंट इंटरफेस पद्धती लागू करा. पद्धत असू शकते:
-
कोणतेही बदल न करता कॉल पास करा
-
डेटा सुधारा किंवा पूरक करा, लक्ष्य पद्धतीवर कॉलची संख्या वाढवा/कमी करा इ.
-
अत्यंत प्रकरणांमध्ये, एखादी विशिष्ट पद्धत विसंगत राहिल्यास, UnsupportedOperationException टाका. असमर्थित ऑपरेशन्स कठोरपणे दस्तऐवजीकरण करणे आवश्यक आहे.
-
-
जर अॅप्लिकेशन क्लायंट इंटरफेसद्वारे फक्त अॅडॉप्टर क्लास वापरत असेल (वरील उदाहरणाप्रमाणे), तर अॅडॉप्टर भविष्यात वेदनारहितपणे विस्तारित केले जाऊ शकते.
GO TO FULL VERSION