اینترفیس
kotlin interface
اینترفیس یک موجودیت مهم در برنامهنویسی شیگراست که هم میتواند حاوی تعریف متدهای انتزاعی (Abstract) و هم پیادهسازی متدهای غیرانتزاعی باشد ولی نمیتواند هیچ نوع حالتی را درون خود ذخیره کند. اینترفیس میتواند حاوی پراپرتی نیز باشد ولی با این شرط که انتزاعی تعریف شود یا پیادهسازی هم داشته باشد. به صورت کلی ساختار اینترفیس در کاتلین مشابه جاوا ۸ است و تفاوت چندانی وجود ندارد. کلاسهای انتزاعی در کاتلین چیزی شبیه اینترفیس هستند ولی تفاوت ظریفی با آن دارند. در کلاسهای انتزاعی، اجباری به انتزاعی بودن پراپرتیها یا پیادهسازی آنها نیست ولی در اینترفیس این اجبار وجود دارد.
روش تعریف اینترفیس در کاتلین
با کلیدواژه interface میتوانید این کار را انجام دهید. اگر دقت کنید تفاوت زیادی با تعریف کلاس ندارد:
1 2 3 4 5 | interface MyInterface { var test: String // abstract property fun foo() // abstract method fun hello() = "Hello there" // method with default implementation } |
نکاتی قابل ملاحظه:
- MyInterface حاوی پراپرتی test و متد ()foo است که هر دو انتزاعی هستند؛
- این اینترفیس همچنین متدی غیرانتزاعی تحت عنوان ()hello دارد.
روش پیادهسازی اینترفیس
خب حالا میخواهیم ببینیم این اینترفیسی که ایجاد کردهایم را چطور باید پیادهسازی کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 | interface MyInterface { val test: Int // abstract property fun foo() : String // abstract method (returns String) fun hello() { // method with default implementation // body (optional) } } class InterfaceImp : MyInterface { override val test: Int = 25 override fun foo() = "Lol" // other code } |
در مثال فوق، کلاس InterfaceImp در واقع اینترفیس MyInterface را پیادهسازی کرده که در آن اعضای انتزاعی اینترفیس (متد ()foo و پراپرتی test رونویسی شدهاند.
طرز کار اینترفیس
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | interface MyInterface { val test: Int fun foo() : String fun hello() { println("Hello there, pal!") } } class InterfaceImp : MyInterface { override val test: Int = 25 override fun foo() = "Lol" } fun main(args: Array<String>) { val obj = InterfaceImp() println("test = ${obj.test}") print("Calling hello(): ") obj.hello() print("Calling and printing foo(): ") println(obj.foo()) } |
خروجی:
1 2 3 | test = 25 Calling hello(): Hello there, pal! Calling and printing foo(): Lol |
همانطور که پیشتر نیز گفتم، اینترفیس میتواند حاوی پراپرتی باشد البته به این شرط که پیادهسازی هم داشته باشد:
1 2 3 4 5 6 7 8 9 10 11 12 | interface MyInterface { // property with implementation val prop: Int get() = 23 } class InterfaceImp : MyInterface { // class body } fun main(args: Array<String>) { val obj = InterfaceImp() println(obj.prop) } |
خروجی:
1 | 23 |
در مثال بالا پراپرتی prop انتزاعی نیست ولی چون داخل اینترفیس پیادهسازی آن موجود است مشکلی ندارد. ولی توجه کنید که داخل اینترفیس چیزی مثل val prop: Int=23 نمیتوانید استفاده کنید.
پیادهسازی دو یا چند اینترفیس داخل کلاس
اگرچه در کاتلین امکان ارثبری چندگانه کلاسها نیست ولی چنین محدودیتی برای اینترفیسها وجود ندارد. یک کلاس میتواند دو یا چندین اینترفیس مختلف را پیادهسازی کند:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | interface A { fun callMe() { println("From interface A") } } interface B { fun callMeToo() { println("From interface B") } } // implements two interfaces A and B class Child: A, B fun main(args: Array<String>) { val obj = Child() obj.callMe() obj.callMeToo() } |
خروجی:
1 2 | From interface A From interface B |
حل مشکل تداخل در ارثبری چندگانه اینترفیسها
فرض کنید دو اینترفیس A و B دارای متد غیرانتزاعی مشابهی تحت عنوان ()callMe باشند. شما این دو اینترفیس را در کلاس C پیادهسازی میکنید. حالا وقتی ()callMe را روی شی ایجاد شده از کلاس C صدا میزنید کدام نسخه فراخوانی میشود؟ بله کامپایلر هم سردرگم میشود و خطا میدهد. مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | interface A { fun callMe() { println("From interface A") } } interface B { fun callMe() { println("From interface B") } } class Child: A, B fun main(args: Array<String>) { val obj = Child() obj.callMe() } |
خروجی:
1 | Error:(14, 1) Kotlin: Class 'C' must override public open fun callMe(): Unit defined in A because it inherits multiple interface methods of it |
برای حل مشکل، باید خودتان پیادهسازی مخصوصی از این تابع داشته باشید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | interface A { fun callMe() { println("From interface A") } } interface B { fun callMe() { println("From interface B") } } class C: A, B { override fun callMe() { super<A>.callMe() super<B>.callMe() } } fun main(args: Array<String>) { val obj = C() obj.callMe() } |
حالا که برنامه را اجرا میکنید خروجی به این صورت خواهد بود:
1 2 | From interface A From interface B |
این پیادهسازی صریحی است که در کلاس C انجام شده است:
1 2 3 4 5 6 | class C: A, B { override fun callMe() { super<A>.callMe() super<B>.callMe() } } |
عبارت ()super<A>.callMe متد ()callMe را از کلاس A فرخوانی میکند. ()super<B>.callMe متد ()callMe که متعلق به کلاس B است را فرخوانی میکند.
kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface kotlin interface