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 استفاده مینماییم و در پایان نیز به بررسی مهمترین وجه تمایز اینترفیسها با کلاسها پرداخته و دیدیم که چگونه میتوان برای یک اینترفیس قابلیت ارثبری از چندین اینترفیس را فراهم نمود و گفتیم که این موضوع قابلیت ارثبری چندگانه را برای کلاسها در زبان جاوا نیز فراهم مینماید.
