آموزش زبان کاتلین – درس ۲۳ (اینترفیس)

نویسنده : سید ایوب کوکبی ۷ دی ۱۳۹۷

طبیعتاً منظورم یوزر اینترفیس یا واسط کاربری نیست. اینترفیس یک موجودیت مهم در برنامه‌نویسی شی‌گراست که هم می‌تواند حاوی تعریف متدهای انتزاعی (Abstract) و هم پیاده‌سازی متدهای غیرانتزاعی باشد ولی نمی‌تواند هیچ نوع حالتی را درون خود ذخیره کند. اینترفیس می‌تواند حاوی پراپرتی نیز باشد ولی با این شرط که انتزاعی تعریف شود یا پیاده‌سازی هم داشته باشد. به صورت کلی ساختار اینترفیس در کاتلین مشابه جاوا ۸ است و تفاوت چندانی وجود ندارد. کلاس‌های انتزاعی در کاتلین چیزی شبیه اینترفیس هستند ولی تفاوت ظریفی با آن دارند. در کلاس‌های انتزاعی، اجباری به انتزاعی بودن پراپرتی‌ها یا پیاده‌سازی آن‌ها نیست ولی در اینترفیس این اجبار وجود دارد.

روش تعریف اینترفیس در کاتلین

با کلیدواژه interface می‌توانید این کار را انجام دهید. اگر دقت کنید تفاوت زیادی با تعریف کلاس ندارد:

interface MyInterface {

    var test: String   // abstract property

    fun foo()          // abstract method
    fun hello() = "Hello there" // method with default implementation
}

نکاتی قابل ملاحظه:

  • MyInterface حاوی پراپرتی test و متد ()foo است که هر دو انتزاعی هستند؛
  • این اینترفیس همچنین متدی غیرانتزاعی تحت عنوان ()hello دارد.

روش پیاده‌سازی اینترفیس

خب حالا می‌خواهیم ببینیم این اینترفیسی که ایجاد کرده‌ایم را چطور باید پیاده‌سازی کنیم:

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 رونویسی شده‌اند.

بخوانید  آموزش زبان کاتلین – درس 20 (ارث‌بری)

طرز کار اینترفیس

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())
}

خروجی:

test = 25
Calling hello(): Hello there, pal!
Calling and printing foo(): Lol

همانطور که پیشتر نیز گفتم، اینترفیس می‌تواند حاوی پراپرتی باشد البته به این شرط که پیاده‌سازی هم داشته باشد:

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)
}

خروجی:

۲۳

در مثال بالا پراپرتی prop انتزاعی نیست ولی چون داخل اینترفیس پیاده‌سازی آن موجود است مشکلی ندارد. ولی توجه کنید که داخل اینترفیس چیزی مثل val prop: Int=23 نمی‌توانید استفاده کنید.

پیاده‌سازی دو یا چند اینترفیس داخل کلاس

اگرچه در کاتلین امکان ارث‌بری چندگانه کلاس‌ها نیست ولی چنین محدودیتی برای اینترفیس‌ها وجود ندارد. یک کلاس می‌تواند دو یا چندین اینترفیس مختلف را پیاده‌سازی کند:

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()
}

خروجی:

From interface A
From interface B

حل مشکل تداخل در ارث‌بری چندگانه اینترفیس‌ها

فرض کنید دو اینترفیس A و B دارای متد غیرانتزاعی مشابهی تحت عنوان ()callMe باشند. شما این دو اینترفیس را در کلاس C پیاده‌سازی می‌کنید. حالا وقتی ()callMe را روی شی ایجاد شده از کلاس C صدا می‌زنید کدام نسخه فراخوانی می‌شود؟ بله کامپایلر هم سردرگم می‌شود و خطا می‌دهد. مثال:

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()
}

خروجی:

Error:(14, 1) Kotlin: Class 'C' must override public open fun callMe(): Unit defined in A because it inherits multiple interface methods of it

برای حل مشکل، باید خودتان پیاده‌سازی مخصوصی از این تابع داشته باشید:

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()
}

حالا که برنامه را اجرا می‌کنید خروجی به این صورت خواهد بود:

From interface A
From interface B

این پیاده‌سازی صریحی است که در کلاس C انجام شده است:

class C: A, B {
    override fun callMe() {
        super<A>.callMe()
        super<B>.callMe()
    }
}

عبارت ()super<A>.callMe متد ()callMe را از کلاس A فرخوانی می‌کند. ()super<B>.callMe متد ()callMe که متعلق به کلاس B است را فرخوانی می‌کند.

بخوانید  تست کدها در اندروید - بخش دوم

سید ایوب کوکبی

نویسنده و مترجم...

0 دیدگاه

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *