Interface در کاتلین — آموزش اینترفیس و پیاده سازی آن + کد
اینترفیس موجودیت مهمی در برنامهنویسی شیگرا است که میتواند شامل تعریف «متُدهای» (Method) انتزاعی و پیادهسازی متدهای غیرانتزاعی باشد. قابلیت استفاده از Interface در کاتلین امکانات بیشتری را در کار با کلاسها در اختیار برنامهنویس قرار میدهد که از جمله آنها پیادهسازی وراثت چندگانه است. در این نوشته ابتدا مفهوم اینترفیس در کاتلین به بیان ساده توضیح داده میشود و سپس برای درک بهتر این مفهوم کاربردی، تفاوت بین کلاس و Interface در کاتلین بیان شده است. در ادامه نیز به کمک مثالهایی نحوه پیادهسازی اینترفیس در کاتلین توضیح داده میشود. همچنین در این نوشتار به موارد مهمی همچون ويژگیهای اینترفیس، پیادهسازی چندگانه Interface در کاتلین و وراثت در اینترفیسها پرداخته شده است.
مفهوم Interface در کاتلین چیست؟
اینترفیسها انواع سفارشی ارائه شده توسط کاتلین هستند که امکان نمونهسازی مستقیم آنها وجود ندارد. در عوض، اینترفیسها شکلی از رفتار را تعریف میکنند که اجرا کننده باید از آنها پیروی کند. با کمک اینترفیسها میتوان آرایههایی داشت که از ماهیت «اشیا» (Object) داخل خود خبر ندارند. این آرایهها صرفاً میدانند که اشیا ذخیره شده چه کارهایی میتوانند انجام دهند.
دلیل استفاده از اینترفیس در کاتلین
اینترفیس در برنامهنویسی شیگرا، ساختاری است که کامپیوتر را وادار میکند تا خصوصیتهایی را به یک شی اختصاص دهد. برای نمونه تصور کنید یک کلاس به نام Cat برای ساختن موجودیت گربه و یک کلاس به نام Cow برای ساخت موجودیت گاو و کلاس دیگری به نام Dog برای ساختن موجودیت سگ وجود داشته باشد.
در کلاسهای بالا عمل صحبت کردن را در نظر بگیرید. برای پیادهسازی این فرآیند باید برای هر کدام کلاسی وجود داشته باشد اما به کمک اینترفیس میتوان یک متد با نام Speak برای هر سه موجودیت پیادهسازی کرد. به بیان ساده استفاده از اینترفیس در کاتلین باعث کاهش حجم کدنویسی و در نتیجه صرفهجویی در زمان میشود.
تفاوت کلاس و اینترفیس در کاتلین چیست؟
مفهوم Interface در کاتلین میتواند شامل «اعلان» (Declare) متدهای انتزاعی و پیادهسازی آنها باشد. اینترفیس در کاتلین امکان ذخیرهسازی وضعیت را ندارد و همین مورد باعث تمایز میان اینترفیس و کلاس انتزاعی (Abstract Class) شده است. اینترفیسها میتوانند ویژگیهایی نیز داشته باشند اما باید انتزاعی باشند یا امکان پیادهسازی دسترسی را فراهم کنند.
چگونه یک Interface در کاتلین ایجاد کنیم؟
پیادهسازی اینترفیس در کاتلین با کلمه کلیدی Interface آغاز میشود و به دنبال آن، نام اینترفیس مورد نظر قرار داده میشود. در ادامه نیز اعضای اینترفیس درون کروشه باز و بسته قرار میگیرند. ویژگی مهمی که در اینترفیسها وجود دارد این است که اعضا هیچ تعریفی از خود ندارند، این تعاریف توسط انواع منطبق (Conforming Types) ارائه میشود.
روش پیاده سازی اینترفیس در کاتلین
Interface در کاتلین را به کمک کلاس یا شی میتوان پیاده سازی کرد. در زمان پیادهسازی اینترفیس، نوع منطبق باید تعریف را برای همه اعضای آن ارائه دهد. برای پیادهسازی اینترفیس، نام نوع سفارشی با یک دو نقطه و سپس نام اینترفیس مورد نظر قرار داده میشود. در ادامه پیادهسازی سادهای از Interface در کاتلین آورده شده است.
interface Vehicle() {
fun start()
fun stop()
}
بعد از ایجاد اینترفیس در کاتلین برای پیادهسازی و استفاده از آن در کلاس به صورت زیر باید عمل کرد.
class Car: Vehicle
مثالی برای نشان دادن پیاده سازی Interface در کاتلین
در ادامه مثالی برای نمایش نحوه پیاده سازی Interface در کاتلین ارائه شده است.
interface Vehicle {
fun start()
fun stop()
}
class Car : Vehicle {
override fun start()
{
println("Car started")
}
override fun stop()
{
println("Car stopped")
}
}
fun main()
{
val obj = Car()
obj.start()
obj.stop()
}
در ادامه خروجی نمونهکد بالا آورده شده است:
Car started Car stopped
در برنامه فوق، اینترفیس Vehicle
دو متد start()
و stop()
را اعلان میکند که باید بازنویسی شوند. کلاس Car
اینترفیس را با استفاده از سینتکس (قواعد نحوی) کلاس پیادهسازی میکند و با کلمه کلیدی override
دو متد مورد نظر را بازنویسی میشوند. در نهایت، تابع main
یک شی از کلاس Car
ایجاد و دو متد مورد نظر را فراخوانی میکند.
اینترفیس در کاتلین با پیاده سازی پیش فرض
Interface در کاتلین میتواند پیادهسازیهای پیشفرض برای توابع داشته باشد. در کد زیر، اینترفیس MyInterface
با پیادهسازی پیشفرض تابع withImplementation
همراه است.
interface MyInterface {
fun withImplementation() {
print("withImplementation() was called")
}
}
در نتیجه کلاسهایی که چنین اینترفیسهایی را پیادهسازی میکنند، این امکان را دارند تا از توابع موجود در Interface بدون پیاده سازی مجدد استفاده کنند.
class MyClass: MyInterface {
// No need to reimplement here
}
val instance = MyClass()
instance.withImplementation()
در کد فوق، کلاس MyClass
بدون نیاز به پیادهسازی مجدد امکان استفاده از تابع پیشفرض withImplementation
را دارد.
معرفی فیلم های آموزش برنامه نویسی اندروید
زبان برنامهنویسی کاتلین (Kotlin Programming Language) در حال حاضر به عنوان یکی از محبوبترین زبانها در میان جامعه توسعهدهندگان نرمافزارهای کاربردی موبایل شناخته میشود. همچنین جامعه توسعهدهندگان آن به سرعت در حال افزایش است. در سال ۲۰۱۷ میلادی (1396 شمسی)، گوگل، کاتلین را به عنوان دومین زبان رسمی برای توسعه اندروید معرفی کرد. از آن زمان تاکنون، رشد بسیار بزرگ و مهمی در تقاضا برای این زبان برنامهنویسی در میان توسعهدهندگان و جوامع کسب و کار به وقوع پیوسته است. گوگل در حال حاضر زبان برنامه نویسی کاتلین را به عنوان یکی از بهترین زبانهای برنامهنویسی برای توسعه اپلیکیشنهای اندرویدی اعلام کرده است. این نشان میدهد که آینده خوبی در انتظار این زبان برنامهنویسی است.
در پلتفرم تم آف، دورههای آموزشی مرتبط با زبان برنامه نویسی کاتلین در مجموعه آموزشهای اندروید قابل دسترسی هستند. دورههای آموزش زبان برنامهنویسی کاتلین در این مجموعه به صورت پروژهمحور و موضوعی قرار داده شدهاند. علاوه بر این، دورههایی نیز برای یادگیری برنامهنویسی اندروید در این مجموعه وجود دارد. در تصویر بالا تنها تعداد کمی از دورههای موجود در این مجموعه آموزشی بهعنوان نمونه آمدهاند.
- برای شروع یادگیری برنامهنویسی کاتلین و دسترسی به همه دورههای آموزش اندروید + اینجا کلیک کنید.
مقادیر و متدهای پیشفرض در اینترفیس کاتلین
متدها در اینترفیس میتوانند مقادیر پیشفرضی برای پارامترهای خود داشته باشند. اگر مقدار پارامتر در زمان فراخوانی تابع ارائه نشده باشد، از مقدار پیشفرض آن استفاده میشود. همچنین متدها نیز میتوانند پیادهسازیهای پیشفرض داشته باشند. از این حالت در مواردی استفاده میشود که متد بازنویسی نشده باشد.
مثالی از کاربرد مقادیر و متدهای پیشفرض در اینترفیس کاتلین
در ادامه مثالی برای نشان دادن مقادیر و متدهای پیشفرض آورده شده است.
interface FirstInterface {
fun add(a: Int, b: Int = 5)
fun print()
{
println("This is a default method defined in the interface")
}
}
class InterfaceDemo : FirstInterface {
override fun add(a: Int, b: Int)
{
val x = a + b
println("Sum is $x")
}
override fun print()
{
super.print()
println("It has been overridden")
}
}
fun main()
{
val obj = InterfaceDemo()
println(obj.add(5))
obj.print()
}
خروجی نمونه کد بالا در زیر آورده شده است.
Sum is 10 This is a default method defined in the interface It has been overridden
در برنامه فوق، اینترفیس FirstInterface
دو متد add()
و print()
را تعریف میکند. متد add()
دارای دو پارامتر است که یکی از آنها دارای مقدار پیشفرض 5 است. همچنین متد print()
نیز به صورت پیشفرض پیادهسازی شده است. بنابراین، وقتی کلاس InterfaceDemo
اینترفیس را پیادهسازی میکند، هر دو متد را بازنویسی میکند و اجرای پیشفرض print()
را با کلمه کلیدی super
فراخوانی میکند. همچنین در تابع main
در زمان فراخوانی متد add()
تنها یک آرگومان مشخص میشود، زیرا به آرگومان دوم یک مقدار پیشفرض داده شده است.
ویژگیهای اینترفیس در کاتلین کدامند؟
دقیقا همانند متدها، اینترفیسها نیز میتوانند دارای ویژگی (Attribute | Property) باشند. با این حال، از آنجا که اینترفیس حالتی ندارد، امکان نمونهسازی آنها وجود ندارد. بنابراین هیچ فیلدی برای نگهداری مقادیر آنها وجود ندارد. در نتیجه، فیلدهای اینترفیس یا انتزاعی هستند یا به صورت پیادهسازی ارائه میشوند.
مثالی برای کاربرد ویژگیهای Interface در کاتلین
در ادامه نمونه کدی برای تعیین ویژگیهای اینترفیس در کاتلین و نحوه بازنویسی و استفاده از آنها در کلاس آورده شده است.
interface InterfaceProperties {
val a : Int
val b : String
get() = "Hello"
}
class PropertiesDemo : InterfaceProperties {
override val a : Int = 5000
override val b : String = "Property Overridden"
}
fun main()
{
val x = PropertiesDemo()
println(x.a)
println(x.b)
}
در ادامه خروجی نمونه کد بالا آورده شده است.
5000 Property Overridden
در برنامه فوق، اینترفیس InterfaceProperties
داری دو ویژگی است. ويژگی a
از نوع عدد صحیح است و ویژگی b
از نوع رشته به صورت گیرنده ارائه میشود. کلاس PropertiesDemo
که اینترفیس InterfaceProperties
را پیادهسازی میکند، دو ویژگی مربوط به این اینترفیس را بازنویسی میکند و برای آنها مقدار جدیدی در نظر میگیرد. در انتها نیز تابع main
شیئی از کلاس را ایجاد میکند. شی ایجاد شده با استفاده از علامت نقطه در سینتکس این زبان به Property-های کلاس دسترسی پیدا میکند.
پیادهسازی چندگانه Interface در کاتلین
گاهی اوقات در برنامه چندین اینترفیس تابع مشابهی را پیادهسازی میکنند، یا همه آنها با هم یک یا چند پیادهسازی را تعریف میکنند. در نتیجه، این نحوه تعریف باعث خطا خواهد شد، به این خاطر که برای کامپایلر برنامه مبهم است که کدام پیادهسازی باید استفاده شود. کلاس مشتق شده باید به صورت دستی فراخوانی مناسب را ارائه دهد.
مثالی از پیادهسازی چندگانه Interface در کاتلین
در ادامه مثالی برای روشن شدن این موضوع آورده شده است.
interface A {
fun notImplemented()
fun implementedOnlyInA() { print("only A") }
fun implementedInBoth() { print("both, A") }
fun implementedInOne() { print("implemented in A") }
}
interface B {
fun implementedInBoth() { print("both, B") }
// only defined
fun implementedInOne()
}
class MyClass: A, B {
override fun notImplemented() { print("Normal implementation") }
// implementedOnlyInA() can by normally used in instances
// class needs to define how to use interface functions
override fun implementedInBoth() {
super.implementedInBoth()
super.implementedInBoth()
}
// even if there's only one implementation,
// there multiple definitions
override fun implementedInOne() {
super.implementedInOne()
print("implementedInOne class implementation")
}
}
در کد بالا کلاس MyClass
از دو اینترفیس A
و B
مشتق شده است. هر دو اینترفیس دارای تابع مشترکی با نام implementedInBoth()
با خروجی متفاوت هستند. بنابراین، کلاس در زمان استفاده از تابع موجود در هر کدام از اینترفیسها باید با کمک کلمه کلیدی super
یا super
به صورت واضح مشخص کند که از پیادهسازی موجود در کدام اینترفیس استفاده میکند.
وراثت در اینترفیس کاتلین
اینترفیسها در کاتلین میتوانند سایر اینترفیسها را نیز به ارث ببرند. زمانی که یک اینترفیس از اینترفیس دیگری ارثبری میکند، این امکان فراهم است تا ويژگیها و متدهای خود را اضافه کند. در بحث پیادهسازی نیز باید برای همه ويژگیها و متدها در هر دو اینترفیس تعریفی ارائه دهد. یک Interface در کاتلین میتواند بیش از یک اینترفیس را به ارث ببرد. در کد زیر مثالی برای نشان دادن وراثت در اینترفیس ارائه شده است.
interface Dimensions {
val length : Double
val breadth : Double
}
interface CalculateParameters : Dimensions {
fun area()
fun perimeter()
}
class XYZ : CalculateParameters {
override val length : Double
get() = 10.0
override val breadth : Double
get()= 15.0
override fun area()
{
println("Area is ${length * breadth}")
}
override fun perimeter()
{
println("Perimeter is ${2*(length+breadth)}")
}
}
fun main()
{
val obj = XYZ()
obj.area()
obj.perimeter()
}
در ادامه نیز خروجی کد بالا آورده شده است.
Area is 150.0 Perimeter is 50.0
در برنامه فوق، اینترفیس Dimensions
دو ویژگی طول و عرض را تعریف میکند. اینترفیس CalculatedParameters
اینترفیس Dimensions
را به ارث میبرد و همچنین دو متد area()
و perimeter()
را اضافه میکند. کلاس XYZ
نیز اینترفیس CalculatedParameters
را پیادهسازی میکند و ویژگیها و متدهای آن را بازنویسی میکند که در نهایت در تابع اصلی برنامه فراخوانی میشوند.
وراثت چندگانه اینترفیس در کاتلین
کلاسها در کاتلین از مفهوم وراثت واحد پیروی میکنند، یعنی هر کلاس فقط میتواند کلاس را به ارث ببرد، اما در مورد اینترفیسها در کاتلین یک کلاس از «وراثت چندگانه» (Multiple Inheritance) پشتیبانی میکند که در زبان برنامه نویسی کاتلین به عنوان «انطباق چندگانه» (multiple conformance) نیز شناخته میشود. در مبحث Interface در کاتلین یک کلاس میتواند بیش از یک اینترفیس را پیادهسازی کند، مشروط بر اینکه تعریفی برای همه اعضای اینترفیس ارائه کند.
مثالی برای نشان دادن وراثت چندگانه اینترفیس در کاتلین
در این بخش از نوشته نمونه کدی برای تعیین نحوه پیادهسازی و کاربرد وراثت چندگانه در Interface در کاتلین آورده شده است.
interface InterfaceProperties {
val a : Int
val b : String
get() = "Hello"
}
interface InterfaceMethods {
fun description()
}
class MultipleInterface : InterfaceProperties, InterfaceMethods {
override val a : Int
get() = 50
override fun description()
{
println("Multiple Interfaces implemented")
}
}
fun main()
{
val obj = MultipleInterface()
obj.description()
}
در ادامه نیز خروجی کد بالا نیز آورده شده است.
Multiple Interfaces implemented
در این برنامه دو اینترفیس InterfaceProperties
و InterfaceMethods
تعریف شدهاند. این اینترفیسها توسط کلاس MultipleInterface
پیادهسازی شدهاند و سپس متدها در تابع main
فراخوانی میشوند.
کلمه کلیدی super در Interface
اگر متد موجود در اینترفیس پیادهسازی پیشفرض خود را داشته باشد، امکان استفاده از کلیدواژه super برای دسترسی به آن متد وجود دارد.
interface MyInterface {
fun funcOne() {
// optional body
print("Function with default implementation")
}
}
در نمونه کد بالا متد funcOne()
دارای پیادهسازی پیشفرض است؛ در نتیجه با استفاده از علامت نقطه در سینتکس این زبان امکان دسترسی به متد اینترفیس وجود دارد. در ادامه نحوه دسترسی به متد مورد نظر با استفاده از کلمه کلیدی super آورده شده است.
super.funcOne()
فواید استفاده از Interface
تا اینجا نکات خوبی در مورد مفهوم، کاربرد و نحوه پیادهسازی اینترفیس در کاتلین بیان شد. در ادامه به صورت مختصر مزایای استفاده از قابلیت Interface در کار با کلاسهای انتزاعی بررسی میشود. بهطور کلی Interfaceها دارای مزایای زیر هستند:
- با استفاده از اینترفیس کارها بیشتر به صورت انتزاعی انجام میشوند و این مورد باعث صرفهجویی در زمان توسعه برنامه خواهد شد.
- برنامهنویس این امکان را خواهد داشت که برای هر کلاسی که براساس یک Interface پیادهسازی میشود، توابع خاص را بنویسد.
- چندین کلاس که از منظر خصوصیات به هم نزدیک هستند را میتوان بر پایه یک Interface پیادهسازی کرد.
- یادگیری اینترفیس در کاتلین درک مفاهیم شیگرایی در این زبان را آسانتر میکند.
- قابلیت وراثت چندگانه در اینترفیسها وجود دارد، درحالی که این موضوع در کلاسهای انتزاعی وجود ندارد.
جمعبندی
در این نوشتار بهطور جامع پیرامون مبحث مهم و کاربردی اینترفیس در کاتلین بحث شد. بهطور کلی ساختار اینترفیس در کاتلین و «جاوا» (Java) مشابه است و تفاوت چندانی ندارد. مرز بین دو مفهوم کلاس و Interface بسیار نزدیک به یکدیگر است. در نتیجه، توانایی تشخیص دادن این دو مفهوم از یکدیگر و همچنین آشنا بودن به تفاوتها و کاربردهای هر کدام برای هر توسعهدهندهای که از زبان برنامهنویسی کاتلین استفاده میکند، بسیار ضروری است.
در این نوشته سعی شد تا مفهوم اینترفیس در کاتلین به سادگی بیان شود. همچنین با ارائه مثالهای متنوعی در زمینههای مختلف کار با Interface، از وراثت گرفته تا پیادهسازی های چندگانه سعی شد تا این مبحث مهم و کاربردی به سادگی درک شود.