این Codelab بخشی از دوره Kotlin Bootcamp برای برنامه نویسان است . اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. بسته به دانش خود، ممکن است بتوانید برخی از بخش ها را مرور کنید. این دوره برای برنامه نویسانی است که زبان شی گرا را می دانند و می خواهند Kotlin را یاد بگیرند.
مقدمه
در این کد لبه، شما یک برنامه Kotlin ایجاد می کنید و با کلاس ها و اشیاء در Kotlin آشنا می شوید. اگر زبان شی گرا دیگری بلد باشید، بیشتر این محتوا برای شما آشنا خواهد بود، اما کاتلین تفاوت های مهمی برای کاهش مقدار کد مورد نیاز برای نوشتن دارد. شما همچنین در مورد کلاس های انتزاعی و تفویض رابط کاربری یاد می گیرید.
به جای ساختن یک برنامه نمونه واحد، درسهای این دوره برای ایجاد دانش شما طراحی شدهاند، اما نیمه مستقل از یکدیگر باشند تا بتوانید بخشهایی را که با آنها آشنا هستید، مرور کنید. برای گره زدن آنها به یکدیگر، بسیاری از نمونه ها از تم آکواریوم استفاده می کنند. و اگر می خواهید داستان کامل آکواریوم را ببینید، دوره Kotlin Bootcamp for Programmers Udacity را بررسی کنید.
آنچه از قبل باید بدانید
- اصول اولیه Kotlin، از جمله انواع، عملگرها و حلقه زدن
- نحو تابع کاتلین
- اصول برنامه نویسی شی گرا
- اصول اولیه یک IDE مانند IntelliJ IDEA یا Android Studio
چیزی که یاد خواهید گرفت
- نحوه ایجاد کلاس ها و دسترسی به خصوصیات در Kotlin
- نحوه ایجاد و استفاده از سازنده کلاس در Kotlin
- نحوه ایجاد یک زیر کلاس و نحوه عملکرد وراثت
- درباره کلاسهای انتزاعی، رابطها، و تفویض رابط
- نحوه ایجاد و استفاده از کلاس های داده
- نحوه استفاده از کلاس های سینگلتون، enums و sealed
کاری که خواهی کرد
- یک کلاس با خصوصیات ایجاد کنید
- یک سازنده برای یک کلاس ایجاد کنید
- یک زیر کلاس ایجاد کنید
- نمونه هایی از کلاس ها و رابط های انتزاعی را بررسی کنید
- یک کلاس داده ساده ایجاد کنید
- در مورد کلاس های تکی، enums، و کلاس های مهر و موم شده بیاموزید
اصطلاحات برنامه نویسی زیر باید قبلاً برای شما آشنا باشد:
- کلاس ها نقشه هایی برای اشیا هستند. به عنوان مثال، یک کلاس
Aquarium
طرحی برای ساخت یک شی آکواریوم است. - اشیا نمونه هایی از کلاس ها هستند. یک شی آکواریوم یک
Aquarium
واقعی است. - ویژگی ها ویژگی های طبقات هستند، مانند طول، عرض و ارتفاع یک
Aquarium
. - متدها که توابع عضو نیز نامیده می شوند، عملکرد کلاس هستند. روشها کارهایی هستند که میتوانید با آن شی «انجام دهید». به عنوان مثال، میتوانید یک شیء
Aquarium
fillWithWater()
را پر کنید. - واسط مشخصاتی است که یک کلاس می تواند پیاده سازی کند. به عنوان مثال، تمیز کردن برای اشیاء غیر از آکواریوم رایج است و تمیز کردن عموماً به روش های مشابه برای اشیاء مختلف انجام می شود. بنابراین می توانید یک رابط به نام
Clean
داشته باشید که متدclean()
را تعریف می کند. کلاسAquarium
می تواند رابطClean
را برای تمیز کردن آکواریوم با یک اسفنج نرم پیاده سازی کند. - بسته ها راهی برای گروه بندی کدهای مرتبط به منظور سازماندهی نگه داشتن آن یا ایجاد کتابخانه ای از کدها هستند. پس از ایجاد یک بسته، می توانید محتویات بسته را به فایل دیگری وارد کنید و از کد و کلاس های موجود در آن مجددا استفاده کنید.
در این کار یک پکیج جدید و یک کلاس با چند ویژگی و متد ایجاد می کنید.
مرحله 1: یک بسته ایجاد کنید
بسته ها می توانند به شما کمک کنند تا کد خود را سازماندهی کنید.
- در قسمت Project ، در زیر پروژه Hello Kotlin ، روی پوشه src کلیک راست کنید.
- New > Package را انتخاب کنید و آن را
example.myapp
.
مرحله 2: یک کلاس با ویژگی ها ایجاد کنید
کلاس ها با کلمه کلیدی class
تعریف می شوند و نام کلاس ها بر اساس قرارداد با یک حرف بزرگ شروع می شود.
- روی بسته example.myapp راست کلیک کنید.
- New > Kotlin File / Class را انتخاب کنید.
- در قسمت Kind ، Class را انتخاب کنید و نام کلاس را
Aquarium
. IntelliJ IDEA نام بسته را در فایل گنجانده و یک کلاسAquarium
خالی برای شما ایجاد می کند. - در داخل کلاس
Aquarium
، ویژگی هایvar
را برای عرض، ارتفاع و طول (به سانتی متر) تعریف و مقداردهی اولیه کنید. خصوصیات را با مقادیر پیش فرض مقداردهی اولیه کنید.
package example.myapp
class Aquarium {
var width: Int = 20
var height: Int = 40
var length: Int = 100
}
در زیر هود، Kotlin به طور خودکار دریافت کننده ها و تنظیم کننده ها را برای ویژگی هایی که در کلاس Aquarium
تعریف کرده اید ایجاد می کند، بنابراین می توانید مستقیماً به ویژگی ها دسترسی داشته باشید، به عنوان مثال myAquarium.length
.
مرحله 3: یک تابع main() ایجاد کنید
یک فایل جدید به نام main.kt
ایجاد کنید تا تابع main()
را نگه دارید.
- در قسمت Project در سمت چپ، روی بسته example.myapp راست کلیک کنید.
- New > Kotlin File / Class را انتخاب کنید.
- در زیر منوی کشویی Kind ، انتخاب را به عنوان File نگه دارید و نام فایل را
main.kt
. IntelliJ IDEA شامل نام بسته است، اما تعریف کلاس برای یک فایل را شامل نمی شود. - یک
buildAquarium()
تعریف کنید و در داخل یک نمونه ازAquarium
ایجاد کنید. برای ایجاد یک نمونه، کلاس را طوری ارجاع دهید که گویی یک تابع است،Aquarium()
. این سازنده کلاس را فراخوانی می کند و نمونه ای از کلاسAquarium
ایجاد می کند، مشابه استفاده ازnew
در زبان های دیگر. - یک تابع
main()
تعریف کنید وbuildAquarium()
را فراخوانی کنید.
package example.myapp
fun buildAquarium() {
val myAquarium = Aquarium()
}
fun main() {
buildAquarium()
}
مرحله 4: یک روش اضافه کنید
- در کلاس
Aquarium
، روشی برای چاپ مشخصات ابعاد آکواریوم اضافه کنید.
fun printSize() {
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm ")
}
- در
main.kt
، درbuildAquarium()
،printSize()
را درmyAquarium
کنید.
fun buildAquarium() {
val myAquarium = Aquarium()
myAquarium.printSize()
}
- برنامه خود را با کلیک بر روی مثلث سبز رنگ کنار تابع
main()
اجرا کنید. نتیجه را رعایت کنید.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm
- در
buildAquarium()
کدی را اضافه کنید تا ارتفاع را روی 60 تنظیم کنید و مشخصات ابعاد تغییر یافته را چاپ کنید.
fun buildAquarium() {
val myAquarium = Aquarium()
myAquarium.printSize()
myAquarium.height = 60
myAquarium.printSize()
}
- برنامه خود را اجرا کنید و خروجی را مشاهده کنید.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm Width: 20 cm Length: 100 cm Height: 60 cm
در این کار، یک سازنده برای کلاس ایجاد میکنید و به کار با خواص ادامه میدهید.
مرحله 1: یک سازنده ایجاد کنید
در این مرحله یک سازنده به کلاس Aquarium
که در اولین وظیفه ایجاد کردید اضافه می کنید. در مثال قبلی، هر نمونه از Aquarium
با همان ابعاد ساخته شده است. میتوانید بعد از ایجاد آن با تنظیم ویژگیها، ابعاد را تغییر دهید، اما سادهتر است که برای شروع اندازه آن را درست کنید.
در برخی از زبان های برنامه نویسی، سازنده با ایجاد متدی در کلاس که همان نام کلاس را دارد، تعریف می شود. در Kotlin، سازنده را مستقیماً در خود اعلان کلاس تعریف میکنید، و پارامترهای داخل پرانتز را طوری مشخص میکنید که گویی کلاس یک متد است. مانند توابع در Kotlin، این پارامترها می توانند مقادیر پیش فرض را شامل شوند.
- در کلاس
Aquarium
که قبلا ایجاد کردید، تعریف کلاس را طوری تغییر دهید که شامل سه پارامتر سازنده با مقادیر پیش فرضlength
،width
وheight
باشد و آنها را به ویژگی های مربوطه اختصاص دهید.
class Aquarium(length: Int = 100, width: Int = 20, height: Int = 40) {
// Dimensions in cm
var length: Int = length
var width: Int = width
var height: Int = height
...
}
- روش فشردهتر Kotlin این است که ویژگیها را مستقیماً با سازنده، با استفاده از
var
یاval
تعریف کنیم، و Kotlin همچنین گیرندهها و تنظیمکنندهها را بهطور خودکار ایجاد میکند. سپس می توانید تعاریف ویژگی را در بدنه کلاس حذف کنید.
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40) {
...
}
- هنگامی که یک شی
Aquarium
با آن سازنده ایجاد می کنید، می توانید هیچ آرگومانی را مشخص نکنید و مقادیر پیش فرض را دریافت کنید، یا فقط تعدادی از آنها را مشخص کنید، یا همه آنها را مشخص کنید و یکAquarium
با اندازه کاملا سفارشی ایجاد کنید. در تابعbuildAquarium()
، راه های مختلف ایجاد یک شیAquarium
را با استفاده از پارامترهای نامگذاری شده امتحان کنید.
fun buildAquarium() {
val aquarium1 = Aquarium()
aquarium1.printSize()
// default height and length
val aquarium2 = Aquarium(width = 25)
aquarium2.printSize()
// default width
val aquarium3 = Aquarium(height = 35, length = 110)
aquarium3.printSize()
// everything custom
val aquarium4 = Aquarium(width = 25, height = 35, length = 110)
aquarium4.printSize()
}
- برنامه را اجرا کنید و خروجی را مشاهده کنید.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm Width: 25 cm Length: 100 cm Height: 40 cm Width: 20 cm Length: 110 cm Height: 35 cm Width: 25 cm Length: 110 cm Height: 35 cm
توجه داشته باشید که لازم نیست سازنده را بیش از حد بارگذاری کنید و برای هر یک از این موارد یک نسخه متفاوت بنویسید (به علاوه چند نسخه دیگر برای ترکیب های دیگر). Kotlin آنچه را که از مقادیر پیشفرض و پارامترهای نامگذاری شده مورد نیاز است ایجاد میکند.
مرحله 2: بلوک های init را اضافه کنید
سازنده های مثال بالا فقط ویژگی ها را اعلام می کنند و مقدار یک عبارت را به آنها اختصاص می دهند. اگر سازنده شما نیاز به کد اولیه بیشتری داشته باشد، می توان آن را در یک یا چند بلوک init
قرار داد. در این مرحله چند بلوک init
را به کلاس Aquarium
اضافه می کنید.
- در کلاس
Aquarium
، یک بلوکinit
برای چاپ که شی در حال تنظیم اولیه است، و یک بلوک دوم برای چاپ حجم به لیتر اضافه کنید.
class Aquarium (var length: Int = 100, var width: Int = 20, var height: Int = 40) {
init {
println("aquarium initializing")
}
init {
// 1 liter = 1000 cm^3
println("Volume: ${width * length * height / 1000} l")
}
}
- برنامه را اجرا کنید و خروجی را مشاهده کنید.
aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 40 cm
aquarium initializing
Volume: 100 l
Width: 25 cm Length: 100 cm Height: 40 cm
aquarium initializing
Volume: 77 l
Width: 20 cm Length: 110 cm Height: 35 cm
aquarium initializing
Volume: 96 l
Width: 25 cm Length: 110 cm Height: 35 cm
توجه داشته باشید که بلوکهای init
به ترتیبی که در تعریف کلاس ظاهر میشوند اجرا میشوند و همه آنها با فراخوانی سازنده اجرا میشوند.
مرحله 3: درباره سازنده های ثانویه بیاموزید
در این مرحله با سازنده های ثانویه آشنا می شوید و یکی را به کلاس خود اضافه می کنید. علاوه بر سازنده اولیه، که میتواند یک یا چند بلوک اولیه داشته باشد، یک کلاس init
میتواند یک یا چند سازنده ثانویه نیز داشته باشد تا امکان اضافه بار سازنده را فراهم کند، یعنی سازندههایی با آرگومانهای مختلف.
- در کلاس
Aquarium
، یک سازنده ثانویه اضافه کنید که با استفاده از کلمه کلیدیconstructor
، تعدادی ماهی را به عنوان آرگومان خود در نظر بگیرد. یک خاصیتval
tank برای حجم محاسبه شده آکواریوم در لیتر بر اساس تعداد ماهی ایجاد کنید. فرض کنید 2 لیتر (2000 سانتی متر 3) آب به ازای هر ماهی، به علاوه کمی فضای اضافی تا آب نریزد.
constructor(numberOfFish: Int) : this() {
// 2,000 cm^3 per fish + extra room so water doesn't spill
val tank = numberOfFish * 2000 * 1.1
}
- در داخل سازنده ثانویه، طول و عرض (که در سازنده اولیه تنظیم شده است) را ثابت نگه دارید و ارتفاع مورد نیاز برای ایجاد حجم داده شده مخزن را محاسبه کنید.
// calculate the height needed
height = (tank / (length * width)).toInt()
- در تابع
buildAquarium()
یک فراخوان برای ایجاد یکAquarium
با استفاده از سازنده ثانویه جدید خود اضافه کنید. اندازه و حجم را چاپ کنید.
fun buildAquarium() {
val aquarium6 = Aquarium(numberOfFish = 29)
aquarium6.printSize()
println("Volume: ${aquarium6.width * aquarium6.length * aquarium6.height / 1000} l")
}
- برنامه خود را اجرا کنید و خروجی را مشاهده کنید.
⇒ aquarium initializing Volume: 80 l Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
توجه داشته باشید که حجم دو بار چاپ می شود، یک بار توسط بلوک init
در سازنده اولیه قبل از اجرای سازنده ثانویه، و یک بار توسط کد موجود در buildAquarium()
.
شما می توانستید کلمه کلیدی constructor
را نیز در سازنده اصلی قرار دهید، اما در بیشتر موارد ضروری نیست.
مرحله 4: یک گیرنده ویژگی جدید اضافه کنید
در این مرحله یک گیرنده خصوصیت واضح اضافه می کنید. کاتلین هنگام تعریف ویژگی ها به طور خودکار گیرنده ها و تنظیم کننده ها را تعریف می کند، اما گاهی اوقات مقدار یک ویژگی نیاز به تنظیم یا محاسبه دارد. به عنوان مثال، در بالا، حجم Aquarium
را چاپ کردید. شما می توانید حجم را به عنوان یک ویژگی با تعریف یک متغیر و یک گیرنده برای آن در دسترس قرار دهید. از آنجایی که volume
باید محاسبه شود، دریافت کننده باید مقدار محاسبه شده را برگرداند که می توانید با یک تابع یک خطی این کار را انجام دهید.
- در کلاس
Aquarium
یک ویژگیInt
به نامvolume
تعریف کنید و یک متدget()
که حجم را در خط بعدی محاسبه می کند تعریف کنید.
val volume: Int
get() = width * height * length / 1000 // 1000 cm^3 = 1 l
- بلوک
init
که حجم را چاپ می کند را بردارید. - کد موجود در
buildAquarium()
که حجم را چاپ می کند را حذف کنید. - در
printSize()
یک خط برای چاپ حجم اضافه کنید.
fun printSize() {
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm "
)
// 1 l = 1000 cm^3
println("Volume: $volume l")
}
- برنامه خود را اجرا کنید و خروجی را مشاهده کنید.
⇒ aquarium initializing Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
ابعاد و حجم مانند قبل است، اما حجم فقط یک بار پس از مقداردهی اولیه شی توسط سازنده اولیه و سازنده ثانویه چاپ می شود.
مرحله 5: یک تنظیم کننده ویژگی اضافه کنید
در این مرحله یک تنظیم کننده ویژگی جدید برای حجم ایجاد می کنید.
- در کلاس
Aquarium
،volume
را بهvar
تغییر دهید تا بتوان آن را بیش از یک بار تنظیم کرد. - با افزودن متد
set()
در زیر گیرنده که ارتفاع را بر اساس مقدار آب ارائه شده مجدداً محاسبه می کند، یک تنظیم کننده برای ویژگیvolume
اضافه کنید. طبق قرارداد، نام پارامتر تنظیم کنندهvalue
است، اما در صورت تمایل می توانید آن را تغییر دهید.
var volume: Int
get() = width * height * length / 1000
set(value) {
height = (value * 1000) / (width * length)
}
- در
buildAquarium()
کد اضافه کنید تا حجم آکواریوم را روی 70 لیتر تنظیم کنید. اندازه جدید را چاپ کنید.
fun buildAquarium() {
val aquarium6 = Aquarium(numberOfFish = 29)
aquarium6.printSize()
aquarium6.volume = 70
aquarium6.printSize()
}
- دوباره برنامه خود را اجرا کنید و ارتفاع و حجم تغییر یافته را مشاهده کنید.
⇒ aquarium initialized
Width: 20 cm Length: 100 cm Height: 31 cm
Volume: 62 l
Width: 20 cm Length: 100 cm Height: 35 cm
Volume: 70 l
تاکنون هیچ اصلاح کننده دید، مانند public
یا private
، در کد وجود نداشته است. به این دلیل که به طور پیشفرض، همه چیز در Kotlin عمومی است، به این معنی که همه چیز در همه جا قابل دسترسی است، از جمله کلاسها، متدها، ویژگیها و متغیرهای عضو.
در کاتلین، کلاسها، اشیا، رابطها، سازندهها، توابع، ویژگیها و تنظیمکنندههای آنها میتوانند اصلاحکنندههای دید داشته باشند:
-
public
یعنی خارج از کلاس قابل مشاهده است. همه چیز به طور پیش فرض عمومی است، از جمله متغیرها و متدهای کلاس. -
internal
به این معنی است که فقط در آن ماژول قابل مشاهده خواهد بود. یک ماژول مجموعه ای از فایل های Kotlin است که با هم کامپایل شده اند، به عنوان مثال، یک کتابخانه یا برنامه. -
private
به این معنی است که فقط در آن کلاس (یا فایل منبع اگر با توابع کار می کنید) قابل مشاهده است. -
protected
همانprivate
است، اما برای هر زیر کلاسی نیز قابل مشاهده خواهد بود.
برای اطلاعات بیشتر به Visibility Modifiers در مستندات Kotlin مراجعه کنید.
متغیرهای عضو
ویژگی های یک کلاس یا متغیرهای عضو به طور پیش فرض public
هستند. اگر آنها را با var
تعریف کنید، قابل تغییر هستند، یعنی قابل خواندن و نوشتن هستند. اگر آنها را با val
تعریف کنید، پس از مقداردهی اولیه فقط خواندنی هستند.
اگر خصوصیتی میخواهید که کد شما بتواند بخواند یا بنویسد، اما کد خارجی فقط بتواند بخواند، میتوانید ویژگی و دریافتکننده آن را عمومی بگذارید و تنظیمکننده را خصوصی اعلام کنید، مانند شکل زیر.
var volume: Int
get() = width * height * length / 1000
private set(value) {
height = (value * 1000) / (width * length)
}
در این کار شما یاد می گیرید که چگونه کلاس های فرعی و ارث بری در Kotlin کار می کنند. آنها شبیه به آنچه در زبان های دیگر دیده اید هستند، اما تفاوت هایی وجود دارد.
در کاتلین، به طور پیشفرض، کلاسها را نمیتوان زیر کلاسبندی کرد. به طور مشابه، ویژگیها و متغیرهای عضو نمیتوانند توسط زیر کلاسها لغو شوند (اگرچه میتوان به آنها دسترسی داشت).
شما باید یک کلاس را به عنوان open
علامت گذاری کنید تا اجازه دهید کلاس فرعی قرار گیرد. به طور مشابه، شما باید ویژگیها و متغیرهای عضو را بهعنوان open
علامتگذاری کنید تا آنها را در زیر کلاس لغو کنید. برای جلوگیری از لو رفتن تصادفی جزئیات پیاده سازی به عنوان بخشی از رابط کلاس، کلمه کلیدی open
مورد نیاز است.
مرحله 1: کلاس آکواریوم را باز کنید
در این مرحله کلاس Aquarium
را open
می کنید تا در مرحله بعد بتوانید آن را لغو کنید.
- کلاس
Aquarium
و تمام خصوصیات آن را با کلمه کلیدیopen
علامت گذاری کنید.
open class Aquarium (open var length: Int = 100, open var width: Int = 20, open var height: Int = 40) {
open var volume: Int
get() = width * height * length / 1000
set(value) {
height = (value * 1000) / (width * length)
}
- یک ویژگی
shape
باز با مقدار"rectangle"
اضافه کنید.
open val shape = "rectangle"
- یک خاصیت
water
آزاد را با یک گیرنده اضافه کنید که 90 درصد حجمAquarium
را برمی گرداند.
open var water: Double = 0.0
get() = volume * 0.9
- کد را به
printSize()
اضافه کنید تا شکل را چاپ کنید و مقدار آب را به صورت درصدی از حجم چاپ کنید.
fun printSize() {
println(shape)
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm ")
// 1 l = 1000 cm^3
println("Volume: $volume l Water: $water l (${water/volume*100.0}% full)")
}
- در
buildAquarium()
کد را تغییر دهید تا یکAquarium
باwidth = 25
،length = 25
وheight = 40
ایجاد کنید.
fun buildAquarium() {
val aquarium6 = Aquarium(length = 25, width = 25, height = 40)
aquarium6.printSize()
}
- برنامه خود را اجرا کنید و خروجی جدید را مشاهده کنید.
⇒ aquarium initializing rectangle Width: 25 cm Length: 25 cm Height: 40 cm Volume: 25 l Water: 22.5 l (90.0% full)
مرحله 2: یک زیر کلاس ایجاد کنید
- یک زیر کلاس از
Aquarium
به نامTowerTank
که یک مخزن استوانه ای گرد را به جای مخزن مستطیلی اجرا می کند. میتوانیدTowerTank
زیرAquarium
اضافه کنید، زیرا میتوانید کلاس دیگری را در همان فایل کلاسAquarium
اضافه کنید. - در
TowerTank
، ویژگیheight
را که در سازنده تعریف شده است، لغو کنید. برای لغو یک ویژگی، از کلمه کلیدیoverride
در زیر کلاس استفاده کنید.
- ساختار سازنده
TowerTank
را بهdiameter
برسانید. هنگام فراخوانی سازنده در سوپرکلاسAquarium
ازdiameter
هم برایlength
و هم برایwidth
استفاده کنید.
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
- برای محاسبه یک استوانه، خاصیت حجم را نادیده بگیرید. فرمول یک استوانه پی ضربدر شعاع مجذور ارتفاع است. شما باید
PI
ثابت را ازjava.lang.Math
وارد کنید.
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
- در
TowerTank
، ویژگیwater
را 80 درصد حجم را نادیده بگیرید.
override var water = volume * 0.8
-
shape
"cylinder"
را لغو کنید.
override val shape = "cylinder"
- کلاس
TowerTank
نهایی شما باید چیزی شبیه به کد زیر باشد.
Aquarium.kt
:
package example.myapp
import java.lang.Math.PI
... // existing Aquarium class
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
override var water = volume * 0.8
override val shape = "cylinder"
}
- در
buildAquarium()
یکTowerTank
با قطر 25 سانتی متر و ارتفاع 45 سانتی متر ایجاد کنید. اندازه را چاپ کنید.
main.kt:
package example.myapp
fun buildAquarium() {
val myAquarium = Aquarium(width = 25, length = 25, height = 40)
myAquarium.printSize()
val myTower = TowerTank(diameter = 25, height = 40)
myTower.printSize()
}
- برنامه خود را اجرا کنید و خروجی را مشاهده کنید.
⇒ aquarium initializing rectangle Width: 25 cm Length: 25 cm Height: 40 cm Volume: 25 l Water: 22.5 l (90.0% full) aquarium initializing cylinder Width: 25 cm Length: 25 cm Height: 40 cm Volume: 18 l Water: 14.4 l (80.0% full)
گاهی اوقات می خواهید رفتار یا ویژگی های مشترکی را برای به اشتراک گذاشتن بین برخی کلاس های مرتبط تعریف کنید. Kotlin دو راه برای انجام این کار ارائه می دهد، رابط ها و کلاس های انتزاعی. در این کار، شما یک کلاس AquariumFish
انتزاعی برای خواصی که برای همه ماهی ها مشترک است ایجاد می کنید. شما یک رابط به نام FishAction
ایجاد می کنید تا رفتار مشترک همه ماهی ها را تعریف کنید.
- نه یک کلاس انتزاعی و نه یک رابط را نمی توان به تنهایی نمونه سازی کرد، به این معنی که شما نمی توانید اشیایی از آن نوع را مستقیماً ایجاد کنید.
- کلاس های انتزاعی سازنده دارند.
- اینترفیس ها نمی توانند منطق سازنده ای داشته باشند یا وضعیتی را ذخیره کنند.
مرحله 1. یک کلاس انتزاعی ایجاد کنید
- در قسمت example.myapp ، یک فایل جدید به نام
AquariumFish.kt
ایجاد کنید. - یک کلاس ایجاد کنید که به آن
AquariumFish
نیز میگویند و آن را باabstract
علامتگذاری کنید. - یک ویژگی
String
،color
اضافه کنید و آن را باabstract
علامت بزنید.
package example.myapp
abstract class AquariumFish {
abstract val color: String
}
- دو زیر کلاس
AquariumFish
،Shark
وPlecostomus
کنید. - از آنجا که
color
انتزاعی است، زیر کلاس ها باید آن را پیاده سازی کنند.Shark
خاکستری وPlecostomus
را طلایی کنید.
class Shark: AquariumFish() {
override val color = "gray"
}
class Plecostomus: AquariumFish() {
override val color = "gold"
}
- در main.kt ، یک
makeFish()
برای تست کلاس های خود ایجاد کنید. یکShark
و یکPlecostomus
را نمونه برداری کنید، سپس رنگ هر کدام را چاپ کنید. - کد تست قبلی خود را در
main()
حذف کنید و یک فراخوانی بهmakeFish()
اضافه کنید. کد شما باید چیزی شبیه به کد زیر باشد.
main.kt
:
package example.myapp
fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()
println("Shark: ${shark.color}")
println("Plecostomus: ${pleco.color}")
}
fun main () {
makeFish()
}
- برنامه خود را اجرا کنید و خروجی را مشاهده کنید.
⇒ Shark: gray Plecostomus: gold
نمودار زیر نشان دهنده کلاس Shark
و کلاس Plecostomus
است که زیر کلاس کلاس انتزاعی، AquariumFish
است.
مرحله 2. یک رابط ایجاد کنید
- در AquariumFish.kt ، یک رابط به نام
FishAction
با متدeat()
ایجاد کنید.
interface FishAction {
fun eat()
}
-
FishAction
را به هر یک از زیر کلاسها اضافه کنید وeat()
را با چاپ کاری که ماهی انجام میدهد پیادهسازی کنید.
class Shark: AquariumFish(), FishAction {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
class Plecostomus: AquariumFish(), FishAction {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
- در تابع
makeFish()
از هر ماهی که ایجاد کردید با فراخوانیeat()
چیزی بخورد.
fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()
println("Shark: ${shark.color}")
shark.eat()
println("Plecostomus: ${pleco.color}")
pleco.eat()
}
- برنامه خود را اجرا کنید و خروجی را مشاهده کنید.
⇒ Shark: gray hunt and eat fish Plecostomus: gold eat algae
نمودار زیر نشان دهنده کلاس Shark
و کلاس Plecostomus
است که هر دو از رابط FishAction
تشکیل شده و پیاده سازی شده اند.
زمان استفاده از کلاس های انتزاعی در مقابل رابط ها
مثالهای بالا ساده هستند، اما وقتی کلاسهای مرتبط زیادی دارید، کلاسهای انتزاعی و رابطها میتوانند به شما کمک کنند طراحی خود را تمیزتر، سازماندهیشدهتر و نگهداری راحتتر داشته باشید.
همانطور که در بالا ذکر شد، کلاس های انتزاعی می توانند سازنده داشته باشند، و رابط ها نمی توانند، اما در غیر این صورت بسیار شبیه هستند. بنابراین، چه زمانی باید از هر کدام استفاده کنید؟
هنگامی که از واسط ها برای نوشتن یک کلاس استفاده می کنید، عملکرد کلاس از طریق نمونه های کلاسی که در آن وجود دارد، گسترش می یابد. ترکیب بندی تمایل دارد استفاده مجدد و استدلال کد را آسان تر از ارث بردن از یک کلاس انتزاعی کند. همچنین، میتوانید از چندین رابط در یک کلاس استفاده کنید، اما فقط میتوانید از یک کلاس انتزاعی زیر کلاسبندی کنید.
ترکیب اغلب منجر به کپسوله سازی بهتر، جفت شدن کمتر (وابستگی متقابل)، رابط های تمیزتر و کدهای قابل استفاده بیشتر می شود. به این دلایل، استفاده از ترکیب با رابط ها طراحی ارجح است. از سوی دیگر، به ارث بردن از یک طبقه انتزاعی تمایل دارد برای برخی از مشکلات مناسب باشد. بنابراین شما باید ترکیب را ترجیح دهید، اما زمانی که وراثت منطقی است، کاتلین به شما اجازه می دهد این کار را نیز انجام دهید!
- اگر روشهای زیادی دارید و یک یا دو پیادهسازی پیشفرض دارید، برای مثال مانند
AquariumAction
زیر، از یک رابط استفاده کنید.
interface AquariumAction {
fun eat()
fun jump()
fun clean()
fun catchFish()
fun swim() {
println("swim")
}
}
- هر زمان که نمی توانید کلاس را کامل کنید از یک کلاس انتزاعی استفاده کنید. به عنوان مثال، با بازگشت به کلاس
AquariumFish
، میتوانید تمامAquariumFish
را به پیادهسازیFishAction
، و یک پیادهسازی پیشفرض برایeat
ارائه دهید در حالی کهcolor
را انتزاعی بگذارید، زیرا واقعاً یک رنگ پیشفرض برای ماهی وجود ندارد.
interface FishAction {
fun eat()
}
abstract class AquariumFish: FishAction {
abstract val color: String
override fun eat() = println("yum")
}
کار قبلی کلاس های انتزاعی، رابط ها و ایده ترکیب بندی را معرفی کرد. تفویض رابط یک تکنیک پیشرفته است که در آن متدهای یک رابط توسط یک شی کمک کننده (یا نماینده) پیاده سازی می شود که سپس توسط یک کلاس استفاده می شود. این تکنیک زمانی میتواند مفید باشد که از یک رابط در یک سری کلاسهای غیرمرتبط استفاده میکنید: عملکرد رابط مورد نیاز را به یک کلاس کمکی جداگانه اضافه میکنید و هر یک از کلاسها از نمونهای از کلاس کمکی برای پیادهسازی عملکرد استفاده میکنند.
در این کار، از تفویض رابط برای افزودن قابلیت به یک کلاس استفاده می کنید.
مرحله 1: ایجاد یک رابط جدید
- در AquariumFish.kt ، کلاس
AquariumFish
را حذف کنید. به جای ارث بردن از کلاسAquariumFish
،Plecostomus
وShark
قرار است رابط هایی را هم برای اکشن ماهی و هم برای رنگ آنها پیاده سازی کنند. - یک رابط جدید به نام
FishColor
کنید که رنگ را به عنوان یک رشته تعریف می کند.
interface FishColor {
val color: String
}
-
Plecostomus
را برای پیاده سازی دو رابط،FishAction
وFishColor
. بایدcolor
را ازFishColor
نادیده بگیرید وeat()
را ازFishAction
.
class Plecostomus: FishAction, FishColor {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
- کلاس
Shark
خود را تغییر دهید تا به جای ارث بردن ازAquariumFish
، دو رابطFishAction
وFishColor
را نیز پیاده سازی کنید.
class Shark: FishAction, FishColor {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
- کد تمام شده شما باید چیزی شبیه به این باشد:
package example.myapp
interface FishAction {
fun eat()
}
interface FishColor {
val color: String
}
class Plecostomus: FishAction, FishColor {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
class Shark: FishAction, FishColor {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
مرحله 2: یک کلاس تک تن درست کنید
سپس، با ایجاد یک کلاس کمکی که FishColor
را پیادهسازی میکند، تنظیمات مربوط به بخش delegation را پیادهسازی میکنید. شما یک کلاس پایه به نام GoldColor
ایجاد می کنید که FishColor
را پیاده سازی می کند - تنها کاری که انجام می دهد این است که رنگ آن طلایی است.
ایجاد چندین نمونه از GoldColor
، زیرا همه آنها دقیقاً یک کار را انجام می دهند. بنابراین Kotlin به شما امکان می دهد کلاسی را اعلام کنید که در آن فقط می توانید یک نمونه از آن را با استفاده از object
کلمه کلیدی به جای class
ایجاد کنید. کاتلین آن یک نمونه را ایجاد می کند و آن نمونه با نام کلاس ارجاع داده می شود. سپس تمام اشیاء دیگر فقط می توانند از این یک نمونه استفاده کنند—هیچ راهی برای ساختن نمونه های دیگر از این کلاس وجود ندارد. اگر با الگوی سینگلتون آشنا هستید، این روشی است که تکتنها را در کاتلین پیادهسازی میکنید.
- در AquariumFish.kt یک شی برای
GoldColor
ایجاد کنید. رنگ را نادیده بگیرید.
object GoldColor : FishColor {
override val color = "gold"
}
مرحله 3: اضافه کردن نمایندگی رابط برای FishColor
اکنون برای استفاده از نمایندگی رابط آماده هستید.
- در AquariumFish.kt ، رد
color
ازPlecostomus
کنید. - کلاس
Plecostomus
را تغییر دهید تا رنگ آن را ازGoldColor
دریافت کنید. این کار را با افزودنby GoldColor
به اعلان کلاس و ایجاد نمایندگی انجام می دهید. چیزی که می گوید این است که به جای پیاده سازیFishColor
، از پیاده سازی ارائه شده توسطGoldColor
استفاده کنید. بنابراین هر بار کهcolor
به آن دسترسی پیدا می کند، بهGoldColor
واگذار می شود.
class Plecostomus: FishAction, FishColor by GoldColor {
override fun eat() {
println("eat algae")
}
}
با کلاس همانطور که هست، تمام پلکوها طلایی خواهند شد، اما این ماهی ها در واقع رنگ های زیادی دارند. شما می توانید با افزودن یک پارامتر سازنده برای رنگ با GoldColor
به عنوان رنگ پیش فرض برای Plecostomus
به این موضوع رسیدگی کنید.
- کلاس
Plecostomus
را تغییر دهید تا درfishColor
با سازنده آن یک پاس داده شود و پیش فرض آن راGoldColor
قرار دهید. تغییر نمایندگی ازby GoldColor
بهby fishColor
.
class Plecostomus(fishColor: FishColor = GoldColor): FishAction,
FishColor by fishColor {
override fun eat() {
println("eat algae")
}
}
مرحله 4: اضافه کردن نمایندگی رابط برای FishAction
به همین ترتیب، میتوانید از تفویض رابط برای FishAction
استفاده کنید.
- در AquariumFish.kt یک کلاس
PrintingFishAction
بسازید کهFishAction
را پیادهسازی میکند، که یکString
،food
میگیرد، سپس آنچه را که ماهی میخورد چاپ میکند.
class PrintingFishAction(val food: String) : FishAction {
override fun eat() {
println(food)
}
}
- در کلاس
Plecostomus
، تابع overrideeat()
را حذف کنید، زیرا آن را با یک نمایندگی جایگزین میکنید. - در اعلامیه
Plecostomus
،FishAction
را بهPrintingFishAction
واگذار کنید و"eat algae"
پاس کنید. - با تمام آن تفویض، هیچ کدی در بدنه کلاس
Plecostomus
وجود ندارد، بنابراین{}
را حذف کنید، زیرا همه موارد لغو توسط تفویض رابط مدیریت می شوند.
class Plecostomus (fishColor: FishColor = GoldColor):
FishAction by PrintingFishAction("eat algae"),
FishColor by fishColor
نمودار زیر کلاسهای Shark
و Plecostomus
را نشان میدهد که هر دو از رابطهای PrintingFishAction
و FishColor
، اما پیادهسازی را به آنها محول میکنند.
تفویض رابط قدرتمند است، و به طور کلی باید نحوه استفاده از آن را هر زمان که ممکن است از یک کلاس انتزاعی در زبان دیگری استفاده کنید، در نظر بگیرید. این به شما امکان می دهد از ترکیب برای وصل کردن رفتارها استفاده کنید، به جای اینکه به زیرکلاس های زیادی نیاز داشته باشید که هر کدام به روشی خاص تخصص دارند.
یک کلاس داده شبیه یک struct
در برخی از زبانهای دیگر است - این کلاس عمدتاً برای نگهداری برخی دادهها وجود دارد - اما یک شی کلاس داده همچنان یک شی است. اشیاء کلاس داده Kotlin دارای مزایای اضافی مانند ابزارهای کاربردی برای چاپ و کپی هستند. در این کار، یک کلاس داده ساده ایجاد میکنید و با پشتیبانی Kotlin برای کلاسهای داده آشنا میشوید.
مرحله 1: یک کلاس داده ایجاد کنید
- برای نگه داشتن کد جدید، یک
decor
بسته جدید را در زیر بسته example.myapp اضافه کنید. روی example.myapp در قسمت Project کلیک راست کرده و File > New > Package را انتخاب کنید. - در بسته، یک کلاس جدید به نام
Decoration
ایجاد کنید.
package example.myapp.decor
class Decoration {
}
- برای تبدیل
Decoration
به یک کلاس داده، پیشوند اعلان کلاس را با کلمه کلیدیdata
قرار دهید. - یک ویژگی
String
به نامrocks
اضافه کنید تا به کلاس مقداری داده بدهید.
data class Decoration(val rocks: String) {
}
- در فایل، خارج از کلاس، یک
makeDecorations()
برای ایجاد و چاپ نمونه ای از یکDecoration
با"granite"
اضافه کنید.
fun makeDecorations() {
val decoration1 = Decoration("granite")
println(decoration1)
}
- یک تابع
main()
برای فراخوانیmakeDecorations()
اضافه کنید و برنامه خود را اجرا کنید. به خروجی معقولی که ایجاد می شود توجه کنید زیرا این یک کلاس داده است.
⇒ Decoration(rocks=granite)
- در
makeDecorations()
دو شیءDecoration
دیگر را که هر دو "تخته" هستند نمونه برداری کنید و آنها را چاپ کنید.
fun makeDecorations() {
val decoration1 = Decoration("granite")
println(decoration1)
val decoration2 = Decoration("slate")
println(decoration2)
val decoration3 = Decoration("slate")
println(decoration3)
}
- در
makeDecorations()
یک عبارت print اضافه کنید که نتیجه مقایسهdecoration1
1 باdecoration2
را چاپ می کند و مورد دوم را کهdecoration2
3 را باdecoration3
مقایسه می کند. از متد ()quals که توسط کلاس های داده ارائه می شود استفاده کنید.
println (decoration1.equals(decoration2))
println (decoration3.equals(decoration2))
- کد خود را اجرا کنید
⇒ Decoration(rocks=granite) Decoration(rocks=slate) Decoration(rocks=slate) false true
مرحله 2. از تخریب استفاده کنید
برای به دست آوردن ویژگی های یک شی داده و اختصاص دادن آنها به متغیرها، می توانید آنها را یکی یکی تخصیص دهید، مانند این.
val rock = decoration.rock
val wood = decoration.wood
val diver = decoration.diver
درعوض، میتوانید متغیرهایی را برای هر ویژگی یکی بسازید و شی داده را به گروه متغیرها اختصاص دهید. کاتلین مقدار ویژگی را در هر متغیر قرار می دهد.
val (rock, wood, diver) = decoration
به این می گویند ساختارشکنی و مختصر مفیدی است. تعداد متغیرها باید با تعداد ویژگی ها مطابقت داشته باشد و متغیرها به ترتیبی که در کلاس اعلان شده اند نسبت داده می شوند. در اینجا یک مثال کامل است که می توانید در Decoration.kt امتحان کنید.
// Here is a data class with 3 properties.
data class Decoration2(val rocks: String, val wood: String, val diver: String){
}
fun makeDecorations() {
val d5 = Decoration2("crystal", "wood", "diver")
println(d5)
// Assign all properties to variables.
val (rock, wood, diver) = d5
println(rock)
println(wood)
println(diver)
}
⇒ Decoration2(rocks=crystal, wood=wood, diver=diver) crystal wood diver
اگر به یک یا چند ویژگی نیاز ندارید، میتوانید با استفاده از _
به جای نام متغیر، همانطور که در کد زیر نشان داده شده است، آنها را نادیده بگیرید.
val (rock, _, diver) = d5
در این کار، با برخی از کلاس های هدف ویژه در کاتلین آشنا می شوید، از جمله موارد زیر:
- کلاس های تک تن
- Enums
- کلاس های مهر و موم شده
مرحله 1: کلاس های تک تن را به یاد بیاورید
مثال قبلی را با کلاس GoldColor
به یاد بیاورید.
object GoldColor : FishColor {
override val color = "gold"
}
از آنجایی که هر نمونه از GoldColor
یک کار را انجام می دهد، به جای اینکه به عنوان یک class
، آن را به یک تک تن تبدیل کند، به عنوان یک object
اعلان می شود. فقط یک نمونه از آن می تواند وجود داشته باشد.
مرحله 2: یک enum ایجاد کنید
Kotlin همچنین از enums پشتیبانی می کند که به شما امکان می دهد چیزی را برشمارید و با نام آن را ارجاع دهید، دقیقاً مانند سایر زبان ها. با قرار دادن پیشوند اعلان با کلمه کلیدی enum
یک enum را اعلام کنید. یک اعلان اولیه فقط به فهرستی از نام ها نیاز دارد، اما می توانید یک یا چند فیلد مرتبط با هر نام را نیز تعریف کنید.
- در Decoration.kt ، نمونه ای از enum را امتحان کنید.
enum class Color(val rgb: Int) {
RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);
}
Enum ها کمی شبیه تک تون ها هستند - از هر مقدار در شمارش فقط یک و فقط یکی می تواند وجود داشته باشد. برای مثال، فقط میتواند یک Color.RED
، یک Color.GREEN
و یک Color.BLUE
باشد. در این مثال، مقادیر RGB به خاصیت rgb
برای نمایش اجزای رنگ اختصاص داده شده است. همچنین می توانید مقدار ترتیبی یک enum را با استفاده از ویژگی ordinal
و نام آن را با استفاده از ویژگی name
بدست آورید.
- نمونه دیگری از enum را امتحان کنید.
enum class Direction(val degrees: Int) {
NORTH(0), SOUTH(180), EAST(90), WEST(270)
}
fun main() {
println(Direction.EAST.name)
println(Direction.EAST.ordinal)
println(Direction.EAST.degrees)
}
⇒ EAST 2 90
مرحله 3: یک کلاس مهر و موم شده ایجاد کنید
کلاس مهر و موم شده، کلاسی است که می توان آن را زیر کلاس قرار داد، اما فقط در داخل فایلی که در آن اعلام شده است. اگر بخواهید کلاس را در فایل دیگری زیر کلاس بندی کنید، با خطا مواجه می شوید.
از آنجایی که کلاسها و زیر کلاسها در یک فایل قرار دارند، کاتلین همه زیر کلاسها را به صورت ایستا میشناسد. یعنی در زمان کامپایل، کامپایلر تمام کلاس ها و زیر کلاس ها را می بیند و می داند که این همه آنهاست، بنابراین کامپایلر می تواند بررسی های اضافی را برای شما انجام دهد.
- در AquariumFish.kt ، یک نمونه از کلاس مهر و موم شده را امتحان کنید، با موضوع آبزیان.
sealed class Seal
class SeaLion : Seal()
class Walrus : Seal()
fun matchSeal(seal: Seal): String {
return when(seal) {
is Walrus -> "walrus"
is SeaLion -> "sea lion"
}
}
کلاس Seal
را نمی توان در فایل دیگری طبقه بندی کرد. اگر می خواهید انواع Seal
بیشتری اضافه کنید، باید آنها را در همان فایل اضافه کنید. این باعث می شود کلاس های مهر و موم شده راهی ایمن برای نشان دادن تعداد ثابتی از انواع باشند. به عنوان مثال، کلاس های مهر و موم شده برای بازگشت موفقیت یا خطا از یک API شبکه عالی هستند.
این درس زمینه های زیادی را پوشش داد. در حالی که بسیاری از آن باید با سایر زبان های برنامه نویسی شی گرا آشنا باشد، کاتلین برخی ویژگی ها را اضافه می کند تا کد را مختصر و خوانا نگه دارد.
کلاس ها و سازنده ها
- با استفاده از
class
یک کلاس در Kotlin تعریف کنید. - کاتلین به طور خودکار تنظیم کننده ها و دریافت کننده ها را برای ویژگی ها ایجاد می کند.
- سازنده اولیه را مستقیماً در تعریف کلاس تعریف کنید. مثلا:
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40)
- اگر سازنده اصلی نیاز به کد اضافی دارد، آن را در یک یا چند بلوک
init
بنویسید. - یک کلاس می تواند یک یا چند سازنده ثانویه را با استفاده از
constructor
تعریف کند، اما سبک Kotlin به این صورت است که به جای آن از یک تابع کارخانه استفاده می کند.
اصلاح کننده های دید و زیر کلاس ها
- همه کلاسها و توابع در Kotlin به طور پیشفرض
public
هستند، اما میتوانید از اصلاحکنندهها برای تغییر قابلیت مشاهده بهinternal
،private
یاprotected
استفاده کنید. - برای ایجاد یک زیر کلاس، کلاس والد باید
open
علامت گذاری شود. - برای نادیده گرفتن متدها و خصوصیات در یک زیر کلاس، متدها و خصوصیات باید در کلاس والد
open
علامت گذاری شوند. - یک کلاس مهر و موم شده را می توان فقط در همان فایلی که در آن تعریف شده است زیر کلاس قرار داد. با قرار دادن پیشوند اعلان با
sealed
یک کلاس مهر و موم شده بسازید.
کلاسهای داده، تکتونها و enums
- با قرار دادن پیشوند اعلان با
data
، یک کلاس داده بسازید. - Destructuring خلاصه ای برای تخصیص ویژگی های یک شی
data
به متغیرهای جداگانه است. - با استفاده از
object
به جایclass
، یک کلاس singleton بسازید. - با استفاده از
enum class
یک enum تعریف کنید.
کلاس های انتزاعی، رابط ها و تفویض اختیار
- کلاسهای انتزاعی و رابطها دو راه برای به اشتراک گذاشتن رفتار مشترک بین کلاسها هستند.
- یک کلاس انتزاعی خصوصیات و رفتار را تعریف می کند، اما پیاده سازی را به زیر کلاس ها واگذار می کند.
- یک رابط رفتار را تعریف می کند و ممکن است اجرای پیش فرض را برای برخی یا همه رفتارها ارائه دهد.
- هنگامی که از واسط ها برای نوشتن یک کلاس استفاده می کنید، عملکرد کلاس از طریق نمونه های کلاسی که در آن وجود دارد، گسترش می یابد.
- تفویض رابط از ترکیب استفاده می کند، اما پیاده سازی را به کلاس های رابط نیز محول می کند.
- Composition یک راه قدرتمند برای افزودن قابلیت به یک کلاس با استفاده از تفویض رابط است. به طور کلی ترکیب بندی ترجیح داده می شود، اما ارث بردن از یک کلاس انتزاعی برای برخی از مشکلات مناسب تر است.
مستندات کاتلین
If you want more information on any topic in this course, or if you get stuck, https://kotlinlang.org is your best starting point.
- Classes and inheritance
- Constructors
- Factory functions
- Properties and fields
- Visibility modifiers
- Abstract classes
- Interfaces
- Delegation
- Data classes
- Equality
- Destructuring
- Object declarations
- Enum classes
- Sealed classes
- Handling Optional Errors Using Kotlin Sealed Classes
Kotlin tutorials
The https://try.kotlinlang.org website includes rich tutorials called Kotlin Koans, a web-based interpreter , and a complete set of reference documentation with examples.
Udacity course
To view the Udacity course on this topic, see Kotlin Bootcamp for Programmers .
IntelliJ IDEA
Documentation for the IntelliJ IDEA can be found on the JetBrains website.
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است به آنها اختصاص دهند.
اگر به تنهایی بر روی این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
یه این سوالات پاسخ دهید
سوال 1
Classes have a special method that serves as a blueprint for creating objects of that class. What is the method called?
▢ A builder
▢ An instantiator
▢ A constructor
▢ A blueprint
سوال 2
Which of the following statements about interfaces and abstract classes is NOT correct?
▢ Abstract classes can have constructors.
▢ Interfaces can't have constructors.
▢ Interfaces and abstract classes can be instantiated directly.
▢ Abstract properties must be implemented by subclasses of the abstract class.
سوال 3
Which of the following is NOT a Kotlin visibility modifier for properties, methods, etc.?
▢ internal
▢ nosubclass
▢ protected
▢ private
Question 4
Consider this data class:
data class Fish(val name: String, val species:String, val colors:String)
Which of the following is NOT valid code to create and destructure a Fish
object?
▢ val (name1, species1, colors1) = Fish("Pat", "Plecostomus", "gold")
▢ val (name2, _, colors2) = Fish("Bitey", "shark", "gray")
▢ val (name3, species3, _) = Fish("Amy", "angelfish", "blue and black stripes")
▢ val (name4, species4, colors4) = Fish("Harry", "halibut")
Question 5
Let's say you own a zoo with lots of animals that all need to be taken care of. Which of the following would NOT be part of implementing caretaking?
▢ An interface
for different types of foods animals eat.
▢ An abstract Caretaker
class from which you can create different types of caretakers.
▢ An interface
for giving clean water to an animal.
▢ A data
class for an entry in a feeding schedule.
Proceed to the next lesson:
For an overview of the course, including links to other codelabs, see "Kotlin Bootcamp for Programmers: Welcome to the course."