در این تکلیف، شما یک سازنده برای کلاس میسازید، و کار با خصوصیات را ادامه میدهید.
گام 1: یک سازنده بسازید
در این گام، شما یک سازنده به کلاس Aquarium که در تکلیف قبل ساختید اضافه میکنید. در مثالهای قبلی، هر نمونه از Aquarium با ابعاد یکسان ساخته میشود. شما میتوانید ابعاد را وقتی که ساخته شد با تنظیم خصوصیات تغییر دهید، اما برای شروع راحتتر است که آن را با اندازههای صحیح بسازید.
در بعضی زبانهای برنامه نویسی، سازنده با ساختن یک متد داخل کلاس که نامی مثل نام کلاس دارد ساخته میشود. در کاتلین، شما سازنده را مستقیما داخل کلاس تعریف میکنید، پارامترها را داخل پرانتز تعریف میکنید اگر کلاس یک متد باشد. مانند تابعها در کاتلین، پارامترها میتوانند شامل مقدار اولیه باشد.
1. در کلاس 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 ... }
2. روش کوتاهتر کاتلین تعریف مستقیم خصوصیات با سازنده است، با استفاده از var یا val، و کاتلین همچنین گیرنده و تنظیم کنندهها را به طور خودکار میسازد. سپس میتوانید تعریف خصوصیتها را در بدنه کلاس عوض کنید.
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40) { ... }
3. وقتی با استفاده از سازنده یک شی 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() }
4. برنامه را اجرا کنید و نتایج را مشاهده کنید.
⇒ 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
توجه کنید که شما نیازی به سربار کردن سازنده و نوشتن نسخههای متفاوت برای هر یک از موارد ندارید (به اضافه تعدادی برای دیگر ترکیبات). کاتلین چیزی که برای ساختن مقادیر پیشفرض و پارامترهای نام دار نیاز است را میسازد.
گام 2: بلوک init اضافه کنید
نمونه سازندههای بالا فقط خصوصیات را اعلام میکنند و مقدار یک عبارت را به آنها تخصیص میدهند. اگر سازنده شما به مقدار دهی اولیه بیشتری نیاز دارد، میتوانید آن را در یک یا چند بلوک init قرار دهید. در این گام، شما چند بلوک init به کلاس Aquarium اضافه میکنید.
1. در کلاس 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") } }
2. برنامه را اجرا کنید و نتایج را ببینید.
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: در مورد سازندههای فرعی (secondary constructors) بیاموزید
در این گام، شما درباره سازنده های فرعی میآموزید و یکی از آنها را به کلاس اضافه میکنید. علاوه بر سازندههای اصلی، که یک یا چند بلوک init دارند، یک کلاس کاتلین همچنین میتواند یک یا چند سازنده فرعی برای سربار کردن سازنده داشته باشد که سازندههایی با آرگومانهای متفاوت هستند.
شیوه کدنویسی کاتلین میگوید هر کلاس باید یک سازنده داشته باشد، با استفاده از مقادیر پیش فرض و پارامترهای نام دار. زیر استفاده از چند سازنده به مسیرهای کدی بیشتر منجر میشود، و امکان اینکه یک یا چند مسیر امتحان نشده باقی بماند را بیشتر میکند. پیش از نوشتن سازنده فرعی، فکر کنید آیا یک تابع کارخانه به جای آن کار میکند یا نه، تا تعریف کلاس را تمیز نگهدارید.
هر سازنده ثانویه باید سازنده اولیه را صدا بزند، یا با استفاده از ()this یا به صورت غیر مستقیم به وسیله یک سازنده فرعی. این یعنی هر بلوک init که داخل سازنده اولیه باشد برای همه سازنده ها صدا زده میشوند، و همه کد داخل سازنده اولیه در ابتدا اجرا میشود.
1. در کلاس Aquarium، یک سازنده فرعی (ثانویه) تعداد ماهی را به عنوان آرگومان میگیرد، با استفاده از کلمه کلیدی constructor. یک خصوصیت val به نام tank برای حجم محاسبه شده آکواریوم به لیتر بر اساس تعداد ماهی بسازید. 2 لیتر آب را برای هر ماهی در نظر بگیرید، به اضافه یک فضای اضافه تا آب به بیرون نریزد.
constructor(numberOfFish: Int) : this() { // 2,000 cm^3 per fish + extra room so water doesn't spill val tank = numberOfFish * 2000 * 1.1 }
2. داخل سازنده فرعی، طول و عرض(که در سازنده اولیه تعریف شدند) را مانند قبل نگه دارید، و ارتفاع لازم برای ساختن حجم داده شده را محاسبه کنید.
// calculate the height needed height = (tank / (length * width)).toInt()
3. داخل تابع ()buildAquarium، برای ساختن Aquarium با استفاده از سازنده فرعی یک فراخوانی بسازید. اندازه و حجم را چاپ کنید.
fun buildAquarium() { val aquarium6 = Aquarium(numberOfFish = 29) aquarium6.printSize() println("Volume: ${aquarium6.width * aquarium6.length * aquarium6.height / 1000} l") }
4. برنامه را اجرا کنید و نتایج را مشاهده کنید.
⇒ aquarium initializing Volume: 80 l Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
توجه کنید که حجم دو بار چاپ شد، یکبار توسط بلوک init در سازنده اصلی پیش از اجرای سازنده فرعی، و یک بار توسط کد داخل ()buildAquarium.
شما کلمه کلیدی constructor را داخل سازنده اولیه هم قرار دادید، اما در بیشتر موارد این الزامی نیست.
گام 4: یک خصوصیت گیرنده اضافه کنید
در این گام، شما یک گیرنده صریح خصوصیت اضافه میکنید. کاتلین وقتی خصوصیات را تعریف کنید به طور خودکار گیرنده ها و تنظیم کننده ها را تعریف میکند، اما بعضی وقت ها مقدار یک خصوصیت نیاز به محاسبه شدن یا تنظیم شدن دارد. برای مثال، در بالا شما حجم Aquarium را چاپ کردید. شما میتوانید حجم را با تعریف کردن یک متغیر و یک گیرنده برای آن به عنوان خصوصیت بسازید. زیرا volume باید محاسبه شود، گیرنده نیاز دارد مقدار محاسبه شده را برگرداند، که شما آن را با یک تابع تک خطی انجام میدهید.
1. در کلاس Aquarium، یک خصوصیت volume از نوع Int تعریف کنید، و یک متد ()get که حجم را در خط بعدی محاسبه میکند تعریف کنید.
val volume: Int get() = width * height * length / 1000 // 1000 cm^3 = 1 l
2. بلوک init چاپ کننده حجم را بردارید.
3. کد داخل ()buildAquarium که حجم را چاپ میکند بردارید.
4. در متد ()printSize، یک خط برای چاپ کردن حجم اضافه کنید.
fun printSize() { println("Width: $width cm " + "Length: $length cm " + "Height: $height cm " ) // 1 l = 1000 cm^3 println("Volume: $volume l") }
5. برنامه را اجرا کنید و نتایج را مشاهده کنید.
⇒ aquarium initializing Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
ابعاد و حجم مانند قبل هستند، اما حجم فقط یکبار بعد از آغاز کامل شی توسط سازنده اصلی و فرعی چاپ میشود.
گام 5: یک خصوصیت تنظیم کننده اضافه کنید
در این گام، شما یک خصوصیت تنظیم کننده (setter) برای حجم میسازید.
1. در کلاس Aquarium، نوع volume را به var تغییر دهید تا بتواند بیش از یکبار تنظیم شود.
2. با اضافه کردن یک متد ()set پایین گیرنده، یک تنظیم کننده برای خصوصیت volume اضافه کنید، که ارتفاع را دوباره بر اساس مقدار آب محاسبه میکند. طبق قراداد، نام پارامتر تنظیم کننده value است، اما شما میتوانید به دلخواه آن را تغییر دهید.
var volume: Int get() = width * height * length / 1000 set(value) { height = (value * 1000) / (width * length) }
3. در ()buildAquarium، یک کد برای تنظیم حجم آکواریوم به 70 لیتر اضافه کنید. اندازه جدید را چاپ کنید.
fun buildAquarium() { val aquarium6 = Aquarium(numberOfFish = 29) aquarium6.printSize() aquarium6.volume = 70 aquarium6.printSize() }
4. برنامه را اجرا کنید و ارتفاع و حجم تبدیل شده را مشاهده کنید.
⇒ 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