کلاسها مفهوم محوری در برنامهنویسی شیءگرا هستند. در Crystal همهچیز یک شیء است، هر شیء یک نوع دارد و میتواند به برخی متدها پاسخ دهد. کلاسها نقشهی ساخت اشیاء هستند و مقادیر اولیهی وضعیت، مانند متغیرها، و پیادهسازیهای رفتار، مانند متدها، را فراهم میکنند. اشیاء نمونههای کلاساند که همهی متغیرهای نمونه و وضعیتها را نگه میدارند.
کلاس با کلیدواژهی class تعریف میشود و پس از آن، اسم کلاس به شکل UpperCamelCase نوشته میشود.
class Account
end
برای ساختن یک نمونه از یک کلاس، اسم کلاس را با متد new فراخوانی کنید.
class Account
end
account = Account.new
در مثال بالا، متغیر account یک نمونه از کلاس Account است.
هنگام ساختن یک نمونه، یک متد ویژه به اسم initialize نقش سازنده را ایفا میکند.
این متد زمانی فراخوانی میشود که یک نمونه ساخته میشود.
سازنده به شما اجازه میدهد وضعیت اولیهی نمونه را تعیین کنید.
متد initialize میتواند آرگومان بگیرد؛ آرگومانها هنگام ساختن نمونه پاس داده میشوند.
class Account
def initialize(number)
5 + number # => 9
end
end
Account.new(4)
متد initialize نمیتواند بهصورت دستی مقداری برگرداند؛ در عوض، new نمونهی تازهساختهشده را برمیگرداند.
class Account
def initialize(number)
5 + number
end
end
Account.new(4)
# => #<Account:0x7f5dc33dcea0>
متد نمونه متدی است که در دسترس یک نمونه از کلاس قرار دارد و میتوان آن را روی آن نمونه فراخوانی کرد.
متدهای نمونه با کلیدواژهی def و پس از آن اسم متد تعریف میشوند.
این متدها داخل تعریف کلاس تعریف میشوند.
class Account
def balance
100
end
end
account = Account.new
account.balance # => 100
متغیرهای نمونه متغیرهایی هستند که در همهی متدهای نمونه در دسترساند.
برای دسترسی به یک متغیر نمونه باید یک متد نمونه تعریف کنید.
میتوان آنها را در متد initialize مقداردهی اولیه کرد.
این متغیرها با پیشوند @ تعریف میشوند.
class Account
def initialize
@balance = 100
end
def balance
@balance
end
end
account = Account.new
account.balance
# => 100
متغیرهای نمونه را میتوان داخل تعریف کلاس هم تعریف کرد.
class Account
@age = 0
end
متغیرهای نمونه را میتوان با آرگومانی که به متد initialize پاس داده میشود مقداردهی اولیه کرد.
از آنجا که Crystal نمیتواند نوع آرگومان بهکاررفته هنگام مقداردهی اولیه را استنتاج کند، باید مشخص شود.
اگر میخواهید دربارهی این موضوع بیشتر بخوانید، میتوانید این را بخوانید: type-inference.
برای مشخص کردن نوع متغیر میتوانید از نماد : و پس از آن نوع استفاده کنید.
برای نمونه، اگر میخواهید یک متغیر نمونه به اسم balance از نوع Int32 بسازید، میتوانید این کار را بکنید: @balance : Int32.
یا اگر میخواهید یک متغیر نمونه به اسم raining از نوع Bool بسازید، میتوانید این کار را بکنید: @raining : Bool.
برای پیادهسازی این کار چند راه وجود دارد؛ یکی اینکه در متد initialize آرگومان را همراه با نوعش اعلام کنید و سپس متغیر نمونه را به آرگومان نسبت دهید، مانند مثال زیر:
class Account
def initialize(balance : Int32)
@balance = balance
end
def balance
@balance
end
end
account = Account.new(1)
account_2 = Account.new(5)
account.balance
# => 1
account_2.balance
# => 5
راه دیگر این است که نوع متغیر نمونه را در تعریف کلاس، به شکل @<variable> : <Type> اعلام کنید، مانند مثال زیر:
class Weather
@raining : Bool
def initialize(raining)
@raining = raining
end
def raining
@raining
end
end
weather = Weather.new(true)
weather.raining
# => true
متدها میتوانند متغیرهای نمونه را تغییر دهند. این متدها را میتوان روی نمونهی کلاس فراخوانی کرد. وقتی متدی یک متغیر نمونه را تغییر میدهد، آن تغییر فقط در همان نمونه از کلاسی که متد را روی آن فراخوانی کردهاید در دسترس است.
class Account
def initialize(balance : Int32)
@balance = balance
end
def withdraw(amount)
@balance -= amount
end
def balance
@balance
end
end
account = Account.new(10)
account_2 = Account.new(10)
account.balance
# => 10
account_2.balance
# => 10
account.withdraw(5)
account.balance
# => 5
account_2.balance
# => 10
متدهای کلاس متدهایی هستند که برای یک کلاس تعریف میشوند، نه برای نمونههای آن.
این متدها راهی برای ساختن متدهایی فراهم میکنند که به وضعیت نمونه وابسته نیستند.
متدهای کلاس با کلیدواژهی def و پس از آن self.<method name> تعریف میشوند.
self ارجاعی است به فضای نامی که self از آن فراخوانی میشود.
در این مورد، به کلاس Account اشاره دارد.
این دقیقاً همان چیزی است که اگر Account. را مینوشتید، اما self. روش ترجیحی است.
class Account
def self.balance
100
end
end
Account.balance
# => 100
دوستتان یوهانس عاشق ساختن سختافزارهای دستساز (خودتان انجام دهید) است. او بهتازگی یک آبمیوهگیری ساخته است و یوهانس خیلی برایش هیجانزده است. هدف یوهانس این است که بتواند هر روز صبح آبمیوهی تازه درست کند.
آبمیوهگیری یوهانس امکانات پیشرفتهی زیادی دارد. مثلاً یک سیستم اندازهگیری داخلی که میتواند به شما بگوید چقدر آبمیوه در لیوان است. یک تایمر هم دارد که به شما میگوید دستگاه چه مدت است کار میکند.
یوهانس در برنامهنویسی بهترین نیست، اما میخواهد برنامهای بنویسد تا دستگاه را کنترل کند. به همین دلیل از شما خواسته است که به او کمک کنید.
دستگاه یک چراغ Debug دارد؛ مکانیزم آن ساده است: اگر دستگاه برق داشته باشد، چراغ Debug روشن است. برنامه فقط زمانی اجرا میشود که چراغ Debug روشن باشد.
این متد باید یک متد کلاس به نام JuiceMaker باشد.
متد کلاس JuiceMaker.debug_light_on? را تعریف کنید که true برمیگرداند.
JuiceMaker.debug_light_on?
#=> true
وقتی دستگاه روشن میشود، باید نمونهای از کلاسی به نام JuiceMaker ساخته شود.
دستگاه باید یک حالت مقداردهیشده داشته باشد.
حالت مقداردهیشده باید اطلاعات زیر را نگه دارد:
false باشد.حالت مقداردهیشده را تعریف کنید، که مقدار آبمیوه در لیوان را به عنوان پارامتر میگیرد، و آن را بسازید.
حالت مقداردهیشده باید یک متغیر نمونهای @running داشته باشد که روی false تنظیم شده است و یک متغیر نمونهای @fluid که بر اساس آرگومانی که هنگام مقداردهی اولیهی کلاس داده میشود تعیین میشود.
JuiceMaker.new(5)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=5>
دستگاه را میتوان روشن و خاموش کرد.
باید متدی برای روشن کردن دستگاه تعریف کنید.
وقتی دستگاه روشن میشود، حالت کار باید روی true تنظیم شود.
متد JuiceMaker#start را تعریف کنید که دستگاه را روشن میکند.
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=true, @fluid=5>
دستگاه باید بتواند وضعیت خودش را به شما بگوید.
اگر دستگاه در حال کار باشد باید true برگرداند و اگر در حال کار نباشد باید false برگرداند.
متد JuiceMaker#running? را تعریف کنید که وضعیت دستگاه را برمیگرداند.
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker.running?
#=> true
دستگاه میتواند به لیوان آبمیوه اضافه کند. دستگاه میتواند بگوید چقدر آبمیوه به لیوان اضافه شده است. دستگاه برای دانستن مقدار آبمیوه در لیوان پس از افزودن آبمیوه به کمک نیاز دارد.
متد JuiceMaker#add_fluid را تعریف کنید، که مقدار آبمیوهی افزودهشده را به عنوان پارامتر میگیرد و مقدار آبمیوه در لیوان را بهروزرسانی میکند.
juice_maker = JuiceMaker.new(5)
juice_maker.add_fluid(5)
juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=10>
دستگاه را میتوان روشن و خاموش کرد.
باید متدی برای خاموش کردن دستگاه تعریف کنید.
این متد فقط زمانی فراخوانی میشود که دستگاه در حال کار باشد.
وقتی دستگاه خاموش میشود، حالت کار باید روی false تنظیم شود.
دستگاه همچنین برای تعیین مقدار آبمیوه در لیوان پس از خاموش شدن به کمک نیاز دارد.
دستگاه در هر دقیقه پنج واحد آبمیوه مصرف میکند.
متد JuiceMaker#stop را تعریف کنید که تعداد دقیقههایی را که دستگاه کار کرده است به عنوان پارامتر میگیرد و مقدار آبمیوه در لیوان را پس از خاموش شدن دستگاه برمیگرداند.
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker
#=> <JuiceMaker:0x10f0b8 @running=true, @fluid=5>
juice_maker.stop(1)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=0>