हाय! आज आपण जावामधील एका महत्त्वाच्या संकल्पनेबद्दल बोलणार आहोत: इंटरफेस. हा शब्द कदाचित तुमच्या परिचयाचा असेल. उदाहरणार्थ, बहुतेक संगणक प्रोग्राम आणि गेममध्ये इंटरफेस असतात. व्यापक अर्थाने, इंटरफेस हा एक प्रकारचा 'रिमोट कंट्रोल' आहे जो दोन परस्परसंवादी पक्षांना जोडतो. दैनंदिन जीवनातील इंटरफेसचे एक साधे उदाहरण म्हणजे टीव्ही रिमोट कंट्रोल. हे दोन ऑब्जेक्ट जोडते — एक व्यक्ती आणि एक टीव्ही — आणि भिन्न कार्ये करते: आवाज वाढवा किंवा कमी करा, चॅनेल स्विच करा आणि टीव्ही चालू करा किंवा बंद करा. एका पक्षाला (व्यक्तीला) इंटरफेसमध्ये प्रवेश करणे आवश्यक आहे (रिमोट कंट्रोलवरील बटण दाबा) दुसऱ्या पक्षाला कृती करण्यासाठी. उदाहरणार्थ, पुढील चॅनेलवर टीव्ही बदलण्यासाठी. आणखी काय, वापरकर्ता करत नाही टीव्ही कसा व्यवस्थित केला जातो किंवा चॅनल बदलण्याची प्रक्रिया अंतर्गतरित्या कशी अंमलात आणली जाते हे जाणून घेणे आवश्यक आहे. वापरकर्त्याला प्रवेश असलेली एकमेव गोष्ट म्हणजे इंटरफेस. इच्छित परिणाम प्राप्त करणे हा मुख्य उद्देश आहे. याचा प्रोग्रामिंग आणि Java शी काय संबंध आहे? सर्व काही :) इंटरफेस तयार करणे हे नियमित वर्ग तयार करण्यासारखेच आहे, परंतु त्याऐवजी शब्द वापरणेवर्ग , आम्ही शब्द इंटरफेस सूचित करतो . चला सर्वात सोपा Java इंटरफेस पाहू, ते कसे कार्य करते आणि आम्हाला याची आवश्यकता का आहे ते पाहू:
तुम्ही
public interface CanSwim {
public void swim();
}
आम्ही CanSwim इंटरफेस तयार केला आहे. हे थोडेसे आमच्या रिमोट कंट्रोलसारखे आहे, परंतु एका 'बटण'सह: स्विम() पद्धत. पण हे रिमोट कंट्रोलर कसे वापरायचे? हे करण्यासाठी, आम्हाला एक पद्धत लागू करणे आवश्यक आहे, म्हणजे आमचे रिमोट कंट्रोल बटण. इंटरफेस वापरण्यासाठी, आमच्या प्रोग्राममधील काही वर्गांनी त्याच्या पद्धती लागू करणे आवश्यक आहे. चला अशा वर्गाचा शोध लावू ज्यांच्या वस्तू 'पोहू शकतात'. उदाहरणार्थ, डक क्लास बसतो:
public class Duck implements CanSwim {
public void swim() {
System.out.println("Duck, swim!");
}
public static void main(String[] args) {
Duck duck = new Duck();
duck.swim();
}
}
"आम्ही येथे काय पाहतो? डक क्लास कॅनस्विम इंटरफेसशी इम्प्लुमेंट्स कीवर्डद्वारे 'संबंधित' आहे . तुम्हाला आठवत असेल की आम्ही दोन वर्गांना वारसा द्वारे संबद्ध करण्यासाठी समान यंत्रणा वापरली, परंतु त्या बाबतीत आम्ही विस्तारित शब्द वापरला. पूर्ण स्पष्टता, आम्ही ' पब्लिक क्लास डक इम्प्लुमेंट्स कॅनस्विम ' चे शब्दशः भाषांतर करू शकतो: 'पब्लिक डक क्लास कॅनस्विम इंटरफेस लागू करतो'. याचा अर्थ इंटरफेसशी संबंधित असलेल्या वर्गाने त्याच्या सर्व पद्धती लागू केल्या पाहिजेत. टीप: आमचा Duck
वर्ग, जसे इंटरफेसची CanSwim
एक swim()
पद्धत आहे आणि त्यात काही तर्कशास्त्र आहे. ही अनिवार्य आवश्यकता आहे. जर आपण फक्त लिहूpublic class Duck implements CanSwim
swim()
क्लासमध्ये मेथड न बनवता Duck
, कंपाइलर आम्हाला एरर देईल: डक अॅबस्ट्रॅक्ट नाही आणि कॅनस्विम मधील अॅबस्ट्रॅक्ट मेथड स्विम() ओव्हरराइड करत नाही का? असे का घडते? आम्ही टीव्ही उदाहरण वापरून त्रुटी समजावून सांगितल्यास, चॅनेल बदलू शकत नाही अशा 'चॅनेल बदला' बटणासह एखाद्याला टीव्ही रिमोट कंट्रोल देण्यासारखे होईल. तुम्ही तुमच्या आवडीनुसार बटण दाबू शकता, परंतु ते कार्य करणार नाही. रिमोट कंट्रोल स्वतःच चॅनेल बदलत नाही: ते फक्त टीव्हीला सिग्नल पाठवते, जे चॅनेल बदलण्याची जटिल प्रक्रिया लागू करते. आणि हे आपल्या बदकासोबत आहे: त्याला कसे पोहायचे हे माहित असणे आवश्यक आहे जेणेकरून त्याला इंटरफेस वापरून म्हटले जाऊ शकते CanSwim
. ते कसे माहित नसल्यास, दCanSwim
इंटरफेस दोन पक्षांना जोडत नाही - व्यक्ती आणि कार्यक्रम. व्यक्ती प्रोग्राममध्ये पोहण्यासाठी swim()
पद्धत वापरण्यास सक्षम होणार नाही. Duck
इंटरफेस कशासाठी आहेत हे आता तुम्हाला अधिक स्पष्टपणे समजले आहे. इंटरफेस वर्तनाचे वर्णन करतो जे इंटरफेसची अंमलबजावणी करणाऱ्या वर्गांमध्ये असणे आवश्यक आहे. 'वर्तणूक' हा पद्धतींचा संग्रह आहे. जर आपल्याला अनेक मेसेंजर तयार करायचे असतील, तर सर्वात सोपी गोष्ट म्हणजे इंटरफेस तयार करणे Messenger
. प्रत्येक मेसेंजरला काय आवश्यक आहे? मूलभूत स्तरावर, ते संदेश प्राप्त करण्यास आणि पाठविण्यास सक्षम असले पाहिजेत.
public interface Messenger{
public void sendMessage();
public void getMessage();
}
आता आम्ही फक्त आमचे मेसेंजर वर्ग तयार करू शकतो जे संबंधित इंटरफेसची अंमलबजावणी करतात. कंपायलर स्वतःच ते आमच्या वर्गात अंमलात आणण्यासाठी आम्हाला 'फोर्स' करेल. टेलिग्राम:
public class Telegram implements Messenger {
public void sendMessage() {
System.out.println("Sending a Telegram message!");
}
public void getMessage() {
System.out.println("Receiving a Telegram message!");
}
}
WhatsApp:
public class WhatsApp implements Messenger {
public void sendMessage() {
System.out.println("Sending a WhatsApp message!");
}
public void getMessage() {
System.out.println("Reading a WhatsApp message!");
}
}
व्हायबर:
public class Viber implements Messenger {
public void sendMessage() {
System.out.println("Sending a Viber message!");
}
public void getMessage() {
System.out.println("Receiving a Viber message!");
}
}
हे कोणते फायदे प्रदान करते? त्यापैकी सर्वात महत्वाचे म्हणजे सैल कपलिंग. कल्पना करा की आम्ही एक प्रोग्राम डिझाइन करत आहोत जो क्लायंट डेटा गोळा करेल. Client
क्लायंट कोणता विशिष्ट मेसेंजर वापरत आहे हे दर्शवण्यासाठी वर्गाला निश्चितपणे फील्डची आवश्यकता आहे . इंटरफेसशिवाय, हे विचित्र दिसेल:
public class Client {
private WhatsApp whatsApp;
private Telegram telegram;
private Viber viber;
}
आम्ही तीन फील्ड तयार केले, परंतु क्लायंटकडे फक्त एक मेसेंजर असू शकतो. आम्हाला फक्त कोणते हे माहित नाही. त्यामुळे क्लायंटशी संवाद साधण्यात सक्षम होण्यासाठी आम्हाला वर्गात प्रत्येक शक्यता जोडावी लागेल. असे दिसून आले की त्यापैकी एक किंवा दोन नेहमीच असतील null
, प्रोग्रामद्वारे पूर्णपणे अनावश्यक. त्याऐवजी आमचा इंटरफेस वापरणे चांगले आहे:
public class Client {
private Messenger messenger;
}
हे लूज कपलिंगचे उदाहरण आहे! वर्गात विशिष्ट मेसेंजर वर्ग निर्दिष्ट करण्याऐवजी Client
, आम्ही फक्त क्लायंटकडे मेसेंजर असल्याचे सूचित करतो. कार्यक्रम चालू असताना नक्की कोणता हे निश्चित केले जाईल. पण यासाठी इंटरफेसची गरज का आहे? ते भाषेत का जोडले गेले? हा एक चांगला प्रश्न आहे — आणि योग्य प्रश्न! आपण सामान्य वारसा वापरून समान परिणाम प्राप्त करू शकत नाही? Messenger
पालक म्हणून वर्ग, आणि , Viber
, Telegram
आणि WhatsApp
मुले म्हणून. खरंच, ते शक्य आहे. पण एक अडचण आहे. तुम्हाला आधीच माहित आहे की, Java ला एकापेक्षा जास्त वारसा नाही. परंतु एकाधिक इंटरफेससाठी समर्थन आहे. एक वर्ग तुम्हाला पाहिजे तितके इंटरफेस लागू करू शकतो. अशी कल्पना करा की आपल्याकडे एक Smartphone
वर्ग आहे ज्यामध्ये एक आहेApp
फील्ड, जे स्मार्टफोनवर स्थापित अॅपचे प्रतिनिधित्व करते.
public class Smartphone {
private App app;
}
अर्थात, अॅप आणि मेसेंजर समान आहेत, परंतु तरीही त्या भिन्न गोष्टी आहेत. मेसेंजरच्या मोबाइल आणि डेस्कटॉप आवृत्त्या असू शकतात, परंतु अॅप विशेषतः मोबाइल अॅपचे प्रतिनिधित्व करते. Telegram
येथे करार आहे — जर आम्ही वारसा वापरला, तर आम्ही क्लासमध्ये ऑब्जेक्ट जोडू शकणार नाही Smartphone
. शेवटी, Telegram
वर्ग एकाच वेळी वारसा मिळवू शकत नाही App
आणि Messenger
! आणि आम्ही आधीच ते वारसा बनवले आहे Messenger
आणि वर्गात जोडले आहे Client
. पण Telegram
वर्ग दोन्ही इंटरफेस सहज अंमलात आणू शकतो! Client
त्यानुसार, आपण क्लासला एक Telegram
ऑब्जेक्ट म्हणून देऊ शकतो आणि वर्गाला तो एक म्हणून Messenger
देऊ शकतो . तुम्ही ते कसे करता ते येथे आहे: Smartphone
App
public class Telegram implements Application, Messenger {
// ...methods
}
public class Client {
private Messenger messenger;
public Client() {
this.messenger = new Telegram();
}
}
public class Smartphone {
private Application application;
public Smartphone() {
this.application = new Telegram();
}
}
आता आपण Telegram
वर्गाचा वापर आपल्याला हवा तसा करत आहोत. काही ठिकाणी, ते एक म्हणून कार्य करते App
. इतर ठिकाणी, ते एक म्हणून कार्य करते Messenger
. तुमच्या लक्षात आले असेल की इंटरफेस पद्धती नेहमी 'रिक्त' असतात, म्हणजे त्यांची अंमलबजावणी नसते. याचे कारण सोपे आहे: इंटरफेस वर्तनाचे वर्णन करतो, परंतु ते त्याची अंमलबजावणी करत नाही. 'इंटरफेस लागू करणाऱ्या सर्व वस्तू CanSwim
पोहण्यास सक्षम असणे आवश्यक आहे': इंटरफेस आपल्याला इतकेच सांगतो. Fish
मासे, बदके आणि घोडे पोहण्याचा विशिष्ट मार्ग , , Duck
आणि साठी एक प्रश्न आहेHorse
वर्ग, इंटरफेस नाही. जसे चॅनल बदलणे हे टीव्हीचे काम आहे. रिमोट तुम्हाला यासाठी एक बटण देतो. तथापि, Java 8 मध्ये एक मनोरंजक जोड दिसली - डीफॉल्ट पद्धती. उदाहरणार्थ, तुमच्या इंटरफेसमध्ये 10 पद्धती आहेत. त्यांपैकी 9 ची वेगवेगळ्या वर्गात वेगवेगळी अंमलबजावणी आहे, परंतु एक सर्वांसाठी समान आहे. पूर्वी, Java 8 पूर्वी, इंटरफेस पद्धतींची कोणतीही अंमलबजावणी नव्हती: कंपाइलरने लगेच त्रुटी दिली. आता तुम्ही असे काहीतरी करू शकता:
public interface CanSwim {
public default void swim() {
System.out.println("Swim!");
}
public void eat();
public void run();
}
कीवर्ड वापरून default
, आम्ही डीफॉल्ट अंमलबजावणीसह इंटरफेस पद्धत तयार केली आहे. आम्हाला इतर दोन पद्धतींसाठी आमची स्वतःची अंमलबजावणी प्रदान करणे आवश्यक आहे — eat()
आणि run()
— अंमलबजावणी करणाऱ्या सर्व वर्गांमध्ये CanSwim
. आम्हाला हे पद्धतीसह करण्याची आवश्यकता नाही swim()
: अंमलबजावणी प्रत्येक वर्गात समान असेल. तसे, तुम्ही पूर्वीच्या टास्कमध्ये इंटरफेस भेटलात, जरी तुम्ही लक्षात घेतले नसले तरीही :) येथे एक ज्वलंत उदाहरण आहे: 
List
आणि Set
इंटरफेससह कार्य केले आहे! अधिक तंतोतंत, तुम्ही त्यांच्या अंमलबजावणीसह कार्य केले आहे — ArrayList
, LinkedList
, HashSet
, इ. समान आकृती स्पष्टपणे एक उदाहरण देते जेथे एक वर्ग एकाच वेळी अनेक इंटरफेस लागू करतो. उदाहरणार्थ, आणि ची LinkedList
अंमलबजावणी करतेList
Deque
(डबल-एंडेड रांग) इंटरफेस. आपण इंटरफेसशी परिचित आहात Map
, किंवा त्याऐवजी, त्याच्या HashMap
अंमलबजावणीसह. तसे, हे आकृती एक वैशिष्ट्य दर्शवते: इंटरफेस इतर इंटरफेस वारसा असू शकतात. इंटरफेस SortedMap
वारसा घेतो Map
, तर Deque
वारसा घेतो Queue
. जर तुम्हाला इंटरफेसमधील संबंध दर्शवायचा असेल तर हे आवश्यक आहे, जेथे एक इंटरफेस दुसर्याची विस्तारित आवृत्ती आहे. इंटरफेससह एक उदाहरण पाहू Queue
. आम्ही अद्याप पुनरावलोकन केले नाहीQueues
, परंतु ते अगदी सोपे आहे आणि स्टोअरमध्ये सामान्य रांग किंवा ओळीसारखे कार्य करते. तुम्ही फक्त रांगेच्या शेवटी आयटम जोडू शकता आणि ते फक्त सुरुवातीपासून घेऊ शकता. काही क्षणी, विकसकांना दोन्ही टोकांना आयटम जोडण्यासाठी आणि घेण्यासाठी रांगेच्या वर्धित आवृत्तीची आवश्यकता असते. म्हणून त्यांनी एक Deque
इंटरफेस तयार केला, जो डबल-एंडेड रांग आहे. यात सामान्य रांगेच्या सर्व पद्धती आहेत. शेवटी, हे डबल-एंडेड रांगेचे मूळ आहे, परंतु ते नवीन पद्धती देखील जोडते.
GO TO FULL VERSION