Interface مفهومی است در زبانهای برنامهنویسی که این امکان را در اختیارمان میگذارد تا توسعهٔ کلاسها هرگز به صورت سلیقهای صورت نگیرد بلکه کلیهٔ دولوپرهایی که در یک تیم نرمافزاری روی پروژهای واحد کار میکنند موظف به تبعیت از چارچوبی خواهند بود که در اینترفیسهای مختلف ترسیم شدهاند. در واقع، اینترفیسها مشابه کلاسها تعریف میشوند اما برخی تفاوتهایی با یکدیگر دارند که در ادامه به بررسی این شباهتها و تفاوتها میپردازیم.
به طور کلی، از جمله شباهتهای مابین کلاسها و اینترفیسها میتوان به موارد زیر اشاره کرد:
- همچون کلاسها، در یک اینترفیس میتوان به تعداد دلخواه متد تعریف کرد.
- همچون کلاسها، در یک اینترفیس میتوان متغیرهای فیلد تعریف کرد.
- همچون کلاسها، یک اینترفیس قابلیت ارثبری از روی اینترفیسی دیگر را دارا است.
- نام فایل مربوط به اینترفیس دقیقاً همنام با اینترفیس میباشد به علاوه اینکه پسوند فایل مذکور نیز
java.
است.
همانطور که پیشتر اشاره کردیم، اینترفیسها در زبان برنامهنویس جاوا همانند کلاسها میباشند اما برخی تفاوتها نیز مابین آنها وجود دارد که برخی از مهمترین آنها عبارتند از:
- یک کلاس فقط و فقط میتواند از یک کلاس دیگر ارثبری کند در حالی که در یک کلاس میتوان بیش از یک اینترفیس را به اصطلاح ایمپلیمنت کرد.
- یک کلاس میتواند حاوی متدهایی دارای نام و بدنۀ مربوط به دستورات داخلی باشد اما در اینترفیسها دستوری داخل بدنهٔ متدها نوشته نمیشود که چنین متدهایی تحت عنوان متدهای Abstract نامیده میشوند (در عین حال، در نسخۀ 8 به بعد جاوا امکان تعریف دستورات داخلی برای برخی متدهای فراهم شده است.)
- بر خلاف کلاسها، از روی اینترفیسها نمیتوان آبجکت ساخت اما چنانچه کلاسی از روی اینترفیسی ایمپلیمنت شده باشد، میتوان از روی اینترفیس مد نظر آبجکتی ساخته و از آن به عنوان جایگزینی برای آبجکت ساختهشده از روی کلاسی استفاده کرد که اینترفیس مذکور را ایمپلیمنت کرده است.
- بر خلاف کلاسها، اینترفیسها قابلیت ارثبری از روی چندین اینترفیس را دارند که این امر قابلیت Multiple Inheritance یا «ارثبری چندگانه» را برای زبان برنامهنویسی جاوا فراهم کرده است.
- بر خلاف کلاسها، یک اینترفیس صرفاً سطح دسترسی
public
میتواند داشته باشد.
نحوۀ ایجاد یک اینترفیس در زبان برنامهنویسی جاوا
در ادامۀ این آموزش قصد داریم تا نحوۀ ایجاد یک اینترفیس در زبان برنامهنوسی جاوا را تشریح نماییم که برای این منظور پروژهای تحت عنوان Interface ایجاد کرده و اینترفیسی به نام ProgrammerOne
در آن میسازیم به طوری که در این اینترفیس قصد داریم تا وظایف کاری یک برنامهنویس را پیادهسازی کنیم که وظیفۀ طراحی رابط کاربری یک نرمافزار را بر عهده دارد که در ابتدا کد مربوط به آن را به صورت زیر تکمیل میکنیم:
public interface ProgrammerOne {
public String myString = "Programmer one has to design the UI.";
public void designTheUI();
}
همانطور که در کد فوق ملاحظه میکنیم، برای ساخت یک اینترفیس میباید از کلیدواژۀ public
استفاده کرده سپس کلیدواژهٔ interface
را آورده و در ادامه یک نام (در این مثال ProgrammerOne
) برای آن انتخاب میکنیم که بدین معنی است که این اینترفیس توسط تمامی کلاسهای موجود در تمامی پکیجهای پروژه قابلدسترسی است و در ادامه همانند ساختار یک کلاس، از علائم { }
استفاده کرده و متدهای مورد نیاز را داخل آن تعریف میکنیم.
به طور مثال، در کد فوق آبجکتی تحت عنوان myString
از روی کلاس String
ساخته و استرینگ «.Programmer one has to design the UI» را بدان منتسب کردهایم که به منزلۀ یک متغیر فیلد برای این اینترفیس میباشد و در ادامه متدی تحت عنوان ()designTheUI
تعریف کردهایم که بر خلاف متدهای تعریفشده در داخل کلاسها، دارای علائم { }
نیست و این مسئله از آنجایی ناشی میشود که متدهای داخل یک اینترفیس صرفاً دارای یک Signature (نام متد و پارامترهای ورودی مد نظر) میباشند و دستورات داخلی آنها در کلاسهایی پیادهسازی میشوند که از اینترفیس مد نظر به اصطلاح ایمپلیمنت شده باشند. به عبارت دیگر، متدهای داخل اینترفیس فقط به صورت انتزاعی تعریف شده سپس وظایف متد مد نظر داخل دو علامت { }
در کلاسی پیادهسازی میشود که قرار است تا آن اینترفیس را ایمپلیمنت کند (جهت کسب اطلاعات بیشتر در رابطه با متغیرهای فیلد به آموزش آشنایی با متغیرهای Local و Field در زبان برنامهنویسی جاوا مراجعه نمایید.)
نحوۀ ایمپلیمنت کردن یک اینترفیس در کلاس
به منظور استفاده از اینترفیس ProgrammerOne
، کلاسی ایجاد میکنیم که این وظیفه را دارا است تا اینترفیس مذکور را ایمپلیمنت نماید که برای این منظور کلاسی تحت عنوان ImplementorClass
ایجاد کرده و در ابتدا کدی به صورت زیر خواهیم داشت:
public class ImplementorClass {
}
همانطور که در زبان برنامهنویسی جاوا از کلیدواژۀ extends
به منظور ارثبری از یک کلاس دیگر استفاده میکنیم، به منظور ایمپلیمنت کردن یک اینترفیس در کلاس مورد نظر نیز کیورد implements
را به کار میگیریم به طوری که ابتدا نام کلاس را نوشته سپس کیورد implements
و در ادامه نام اینترفیس مد نظر را مینویسیم. در همین راستا، چنانچه بخواهیم تا اینترفیس ProgrammerOne
را در کلاس ImplementorClass
استفاده کنیم، کدی مانند زیر خواهیم داشت:
public class ImplementorClass implements ProgrammerOne{
}
در ادامه، به منظور تکمیل دستورات داخلی متد ()designTheUI
که آن را به صورت انتزاعی در اینترفیس ProgrammerOne
ایجاد کردهایم، کدهای کلاس ImplementorClass
را به صورت زیر تکمیل میکنیم:
public class ImplementorClass implements ProgrammerOne {
public void designTheUI() {
System.out.println(ProgrammerOne.myString);
}
}
در کد فوق، داخل کلاس ImplementorClass
متد ()designTheUI
از اینترفیس ProgrammerOne
را پیادهسازی نمودهایم که این وظیفه را دارا است تا در صورت فراخوانی، استرینگ منتسب به فیلدِ myString
از اینترفیس ProgrammerOne
را در کنسول چاپ نماید. در ادامه، جهت فراخوانی متد ()designTheUI
نیاز به ساخت کلاسی داریم که نقطۀ شروع برنامۀ ما باشد که برای این منظور کلاس دیگری تحت عنوان ActionClass
ساخته و به خاطر داشته باشیم که در حین ساخت کلاس تیک گزینۀ public static void main را بزنیم به طوری که در ابتدا کد مربوط به کلاس ActionClass
به صورت زیر خواهد بود:
public class ActionClass {
public static void main(String[] args) {
}
}
در ادامه، میباید آبجکتی از روی کلاس ImplementorClass
در کلاس ActionClass
ساخته سپس متد ()designTheUI
را روی آن فراخوانی نماییم که برای این منظور کد فوق را به صورت زیر تکمیل میکنیم:
public class ActionClass {
public static void main(String[] args) {
ImplementorClass test = new ImplementorClass();
test.designTheUI();
}
}
در واقع، برای اجرای برنامۀ فوق نیاز به تکمیل متد ()main
داریم و برای این منظور هم در متد مذکور آبجکتی تحت عنوان test
از روی کلاس ImplementorClass
ایجاد کردهایم (جهت کسب اطلاعات بیشتر در رابطه با نحوۀ ساخت آبجکت از روی کلاس، به آموزش مقدمهای بر مفهوم شیئگرایی در زبان برنامهنویسی جاوا مراجعه نمایید.) حال نام آبجکت ساختهشده از روی کلاس ImplementorClass
را نوشته سپس یک .
قرار میدهیم و در ادامه نام متدی را مینویسیم که در اینترفیس ProgrammerOne
تعریف کردهایم. اکنون برنامۀ فوق را اجرا کرده و در خروجی خواهیم داشت:
Programmer one has to design the UI.
همانطور که میبینیم، با موفقیت توانستیم یک اینترفیس ایجاد کنیم سپس آن را در کلاس خود اصطلاحاً ایمپلیمنت کرده و در نهایت با ساخت یک آبجکت از روی کلاس مربوطه توانستیم برنامهای را اجرا نماییم که حاوی یک اینترفیس، کلاس و متد میباشد.
نحوۀ ایمپلیمنت کردن بیش از یک اینترفیس در یک کلاس
یک کلاس قابلیت ایمپلیمنت کردن چندین اینترفیس به صورت همزمان را دارا است که در این صورت میباید تمامی متدهای انتزاعی تعریفشده در تمامی اینترفیسهایی را پیادهسازی نماید که از روی آنها ایمپلیمنت شده است. برای درک بهتر این موضوع، ابتدا یک اینترفیس دیگر تحت عنوان ProgrammerTwo
به صورت زیر تعریف مینماییم:
public interface ProgrammerTwo {
public String stringTwo = "Programmer two has to develop the Application.";
public void appDevelopment();
}
در کد فوق، با استفاده از کیورد interface
اینترفیسی تحت عنوان ProgrammerTwo
ساختهایم که در آن آبجکتی از روی کلاس String
تحت عنوان stringTwo
تعریف کرده و استرینگ «.Programmer two has to develop the Application» را بدان منتسب کردهایم؛ سپس یک متد تحت عنوان ()appDevelopment
تعریف کردهایم که این متد صرفاً دارای Signature (نام متد و در صورت نیاز پارامتر ورودی) بوده و نمیتوان دستوری در آن پیادهسازی کرد بلکه بدنۀ مربوط به دستورات داخلی متدها در کلاسهایی پیادهسازی میشوند که اینترفیس مد نظر را ایمپلیمنت نمایند. در ادامه، جهت استفاده از اینترفیس ProgrammerTwo
در کلاس ImplementorClass
به روش زیر عمل میکنیم:
public class ImplementorClass implements ProgrammerOne, ProgrammerTwo {
public void designTheUI() {
System.out.println(ProgrammerOne.myString);
}
}
همانطور که در کد فوق میبینیم، کلاس ImplementorClass
اینترفیس ProgrammerOne
را ایمپلیمنت کرده و چنانچه بخواهیم اینترفیس دیگری را در این کلاس ایمپلیمنت نماییم، کافی است تا پس از نام اینترفیس اول یک علامت ,
قرار داده و در ادامه نام اینترفیس مد نظر خود را بنویسیم. همانطور که میبینیم، در کد فوق نیز پس از ,
نام اینترفیس ProgrammerTwo
را نوشتهایم و توجه داشته باشیم که در چنین شرایطی میباید حتماً تمامی متدهای انتراعیِ تعریفشده در هر دو اینترفیس را در کلاس مربوطه پیادهسازی نماییم. بنابراین به منظور پیادهسازی متد ()appDevelopment
از اینترفیس ProgrammerTwo
کد فوق را به صورت زیر تکمیل مینماییم:
public class ImplementorClass implements ProgrammerOne, ProgrammerTwo {
public void designTheUI() {
System.out.println(ProgrammerOne.myString);
}
public void appDevelopment() {
System.out.println(ProgrammerTwo.stringTwo);
}
}
در کد فوق، متد ()appDevelopment
را به نحوی پیادهسازی کردهایم تا در صورت فراخوانی استرینگ منتسب به فیلد stringTwo
از اینترفیس ProgrammerTwo
را در کنسول چاپ نماید. در ادامه، به منظور فراخوانی متد مذکور به کلاس ActionClass
مراجعه کرده و آن را روی آبجکت ساختهشده از روی کلاس ImplementorClass
فراخوانی میکنیم که برای این منظور کد مربوط به کلاس ActionClass
را به صورت زیر تکمیل مینماییم:
public class ActionClass {
public static void main(String[] args) {
ImplementorClass test = new ImplementorClass();
test.designTheUI();
test.appDevelopment();
}
}
در ادامه، برنامۀ فوق را اجرا کرده و در خروجی خواهیم داشت:
Programmer one has to design the UI.
Programmer two has to develop the Application.
همانطور که میبینیم، استرینگهای مربوط به هر دو متد از اینترفیسهای متناظرشان در کنسول چاپ شدهاند.
نحوۀ ارثبری اینترفیسها از یکدیگر
همانطور که در ابتدای آموزش اشاره کردیم، یک اینترفیس قابلیت ارثبری از روی اینترفیسهای دیگر را دارا است که در این صورت اینترفیس فرزند تمامی فیلدها و متدهای اینترفیس والد را به ارث میبرد مضاف بر اینکه مشابه کلاسها، به منظور ارثبری دو اینترفیس از یکدیگر از کیورد extends
استفاده میکنیم. برای مثال، چنانچه بخواهیم تا اینترفیس ProgrammerTwo
از اینترفیس ProgrammerOne
ارثبری نماید، کدی مانند زیر خواهیم داشت:
public interface ProgrammerTwo extends ProgrammerOne {
public String stringTwo = "Programmer two has to develop the Application.";
public void appDevelopment();
}
در کد فوق، ابتدا اینترفیس ProgrammerTwo
با استفاده از کیورد extends
از اینترفیس ProgrammerOne
ارثبری کرده و بدین ترتیب فیلد myString
و همچنین متد ()designTheUI
را نیز به ارث میبرد که در چنین شرایطی اگر بخواهیم تا در کلاسی از اینترفیسِ والدِ ProgrammerTwo
استفاده نماییم، میباید حتماً تمامی متدهای انتراعی هر دو اینترفیسِ والدِ ProgrammerTwo
و اینترفیسِ فرزندِ ProgrammerOne
را پیادهسازی نماییم. برای مثال، در ادامه قصد داریم تا اینترفیس ProgrammerTwo
را در کلاس ImplementorClass
استفاده نماییم که برای این منظور کدی مانند زیر خواهیم داشت:
public class ImplementorClass implements ProgrammerTwo{
public void designTheUI() {
System.out.println(ProgrammerOne.myString);
}
public void appDevelopment() {
System.out.println(ProgrammerTwo.stringTwo);
}
}
همانطور که میبینیم، متد انتزاعی ()designUI
از اینترفیس فرزند ProgrammerOne
در کلاسی پیادهسازی شده است که در آن قصد استفاده از اینترفیس والدِ ProgrammerTwo
را داریم که در این متد گفتهایم در صورت فراخوانی، استرینگ منتسب به فیلد myString
از اینترفیس ProgrammerOne
در کنسول چاپ گردد. در ادامه، به منظور فراخوانی متدهای ()designUI
و ()appDevelopment
به کلاس ActionClass
بازگشته و آنها را روی آبجکت ساختهشده از روی کلاس ImplementorClass
فراخوانی مینماییم به طوری که در کد زیر داریم:
public class ActionClass {
public static void main(String[] args) {
ActionClass test = new ActionClass();
test.designTheUI();
test.appDevelopment();
}
}
همانطور که در کد فوق میبینیم، هر دو متد ()designTheUI
و ()appDevelopment
را در کلاس ActionClass
روی آبجکت test
فراخوانی نمودهایم به طوری که اگر برنامه را اجرا کنیم در خروجی خواهیم داشت:
Programmer one has to design the UI.
Programmer two has to develop the Application.
همانطور که ملاحظه میکنیم، هر دو استرینگ مربوط به اینترفیسهای مذکور در کنسول چاپ شدهاند بدین معنی که با ایمپلیمنت کردن متدهای مربوط به اینترفیس والد و فرزند در کلاسی که اینترفیس والد را مورد استفاده قرار داده است، توانستهایم با ساخت آبجکت از روی کلاس مذکور آنها را فراخوانی و اجرا نماییم.
نحوۀ ارثبری چندگانۀ اینترفیسها از یکدیگر
در بخش مربوط به تفاوتهای مابین اینترفیسها و کلاسها گفتیم که بر خلاف کلاسها، یک اینترفیس قابلیت ارثبری چندگانه را دارا است بدین معنی که یک اینترفیس به صورت همزمان میتواند از چندین اینترفیس ارثبری کند که برای این منظور میتوانیم از کیورد extends
استفاده کرده و نام اینترفیسهایی را بنویسیم که قصد داریم تا از آنها ارثبری کنیم (توجه داشته باشیم نام اینترفیسها را میباید با علامت ,
از هم جدا نماییم. به علاوه، در چنین شرایطی میباید تمامی متدهای اینترفیسهای فرزند را در کلاسی پیادهسازی نماییم که اینترفیس والد در آن ایمپلیمنت میشود.)
برای مثال، در ادامه یک اینترفیس دیگر تحت عنوان ProgrammerThree
ساخته به طوری که قصد داریم تا اینترفیس ProgrammerTwo
از دو اینترفیس ProgrammerThree
و ProgrammerOne
ارثبری کند:
public interface ProgrammerThree {
public String stringThree = "Programmer three has to test the Application.";
public void testApp();
}
ساختار اینترفیس ProgrammerThree
مشابه دو اینترفیس پیشین بوده و از همین روی از تفسیر آن خودداری میکنیم. اکنون چنانچه بخواهیم تا اینترفیس ProgrammerTwo
از دو اینترفیس ProgrammerThree
و ProgrammerOne
ارثبری کند، به روش زیر عمل میکنیم:
public interface ProgrammerTwo extends ProgrammerOne, ProgrammerThree {
public String stringTwo = "Programmer two has to develop the Application.";
public void appDevelopment();
}
همانطور که میبینیم، در کد فوق ابتدا نام اینترفیس ProgrammerTwo
را نوشته سپس کیورد extends
را درج کرده و در ادامه نام دو اینترفیس ProgrammerThree
و ProgrammerOne
را نوشتهایم و آنها را با علامت ,
از هم جدا کردهایم که بدین ترتیب اینترفیس ProgrammerTwo
تمامی فیلدها و متدهای دو اینترفیس مذکور را به ارث میبرد. بنابراین به منظور پیادهسازی متد تعریفشده در اینترفیس ProgrammerThree
میباید به کلاس ActionClass
مراجعه نماییم چرا که اینترفیسِ والدِ ProgrammerTwo
را ایمپلمینت کرده است و میتوانیم دستورات متد ()testApp
را در آن پیادهسازی میکنیم. بنابراین کد مربوط به کلاس ImplementorClass
را به صورت زیر تکمیل میکنیم:
public class ImplementorClass implements ProgrammerTwo {
public void designTheUI() {
System.out.println(ProgrammerOne.myString);
}
public void appDevelopment() {
System.out.println(ProgrammerTwo.stringTwo);
}
public void testApp() {
System.out.println(ProgrammerThree.stringThree);
}
}
در کد فوق، متد ()testApp
از اینترفیس فرزندِ ProgrammerThree
را در کلاسی پیادهسازی کردهایم که اینترفیسِ والدِ ProgrammerTwo
در آن ایمپلیمنت شده است به گونهای که در صورت فراخوانی، استرینگ منتسب به stringThree
از اینترفیس مذکور را در کنسول چاپ مینماید. در ادامه، به منظور فراخوانی متدهای فوق به کلاس ActionClass
بازگشته و در داخل متد ()main
متدهای مورد نظر را روی آبجکت test
فراخوانی مینماییم که برای این منظور کد مربوط به کلاس ActionClass
به صورت زیر خواهد بود:
public class ActionClass {
public static void main(String[] args) {
ImplementorClass test = new ImplementorClass();
test.designTheUI();
test.appDevelopment();
test.testApp();
}
}
حال اگر برنامۀ فوق را اجرا کنیم در خروجی خواهیم داشت:
Programmer one has to design the UI.
Programmer two has to develop the Application.
Programmer three has to test the Application.
همانطور که انتظار داشتیم، هر سه استرینگ مربوط به اینترفیسهای تعریفشده در این آموزش در کنسول چاپ شدهاند.
در این آموزش ابتدا به بررسی نحوۀ ایجاد یک اینترفیس پرداخته و در ادامه دیدیم که چگونه میتوان آن را در کلاسی دیگری به اصطلاح ایمپلیمنت کرد؛ سپس نحوۀ ایمپلیمنت کردن چند اینترفیس در یک کلاس را تشریح کردیم. در ادامه، نحوۀ ارثبری دو اینترفیس از یکدیگر را مورد بررسی قرار دادیم و گفتیم که برای این منظور نیز مشابه ارثبری دو کلاس از یکدیگر عمل کرده و از کیورد extends
استفاده مینماییم و در پایان نیز به بررسی مهمترین وجه تمایز اینترفیسها با کلاسها پرداخته و دیدیم که چگونه میتوان برای یک اینترفیس قابلیت ارثبری از چندین اینترفیس را فراهم نمود و گفتیم که این موضوع قابلیت ارثبری چندگانه را برای کلاسها در زبان جاوا نیز فراهم مینماید.