ماژولها در Crystal دو کاربرد دارند:
کاربرد اول، ساختن یک فضای نام برای جلوگیری از تداخل اسمها است. با این حال، کد را هم گروهبندی میکند و همین درک هدف کد را آسانتر میکند.
کاربرد دوم، تعریف میکسینها برای به اشتراک گذاشتن کد با نوعها است.
ماژولها شبیه کلاسها هستند، اما تفاوت اصلی این است که نمیتوان آنها را نمونهسازی کرد و در نتیجه متغیر نمونهای ندارند.
برای اعلام یک ماژول، از کلیدواژهی module استفاده میکنید و بعد از آن اسم ماژول را مینویسید.
module Foo
end
فضای نام روشی برای گروهبندی کد است.
این کار از تداخل اسمها جلوگیری میکند و درک هدف کد را آسانتر میسازد.
وقتی میخواهید به ثابت یا کلاسی دسترسی پیدا کنید که داخل یک فضای نام قرار گرفته است، از عملگر :: استفاده میکنید.
module Foo
class Bar
end
end
Foo::Bar.new
این کار میتواند مفید باشد، برای مثال وقتی چندین کلاس به یک کارکرد «پایه»ی یکسان نیاز دارند یا وقتی باید کد میان کلاسهای بیربط به اشتراک گذاشته شود. یا وقتی میخواهید کد را میان کلاسهایی به اشتراک بگذارید که به هم مربوط نیستند.
دو روش متفاوت برای استفاده از یک ماژول بهعنوان میکسین وجود دارد: روش اول استفاده از کلیدواژهی include است و روش دوم استفاده از کلیدواژهی extend.
هر دو روش ثابتها را برای نوعی که ماژول را include یا extend میکند در دسترس قرار میدهند.
کلیدواژهی include همهی متدهای ماژول را بهصورت متدهای نمونهای روی نوعی که ماژول را include میکند در دسترس قرار میدهد.
کلیدواژهی include باید در بالای نوع نوشته شود و بعد از آن اسم ماژول بیاید.
module Foo
def foo
"foo"
end
end
class Bar
include Foo
end
Bar.new.foo # => "foo"
کلیدواژهی extend شبیه include کار میکند، اما بهجای اینکه متدها را بهصورت متدهای نمونهای در دسترس قرار دهد، آنها را بهصورت متدهای کلاسی در دسترس قرار میدهد.
کلیدواژهی extend باید در بالای نوع نوشته شود و بعد از آن اسم ماژول بیاید.
module Foo
def foo
"foo"
end
end
class Bar
extend Foo
end
Bar.foo # => "foo"
یک الگوی رایج در Crystal استفاده از الگوی extend self در یک ماژول است.
این کار همهی متدهای ماژول را بهصورت متدهای کلاسی روی خود ماژول در دسترس قرار میدهد.
یعنی لازم نیست هر متد را با نحوهی نگارش def self.method_name به ماژول نسبت دهید.
module Foo
extend self
def foo
"foo"
end
end
Foo.foo # => "foo"
«Bellebrook Basketball League» یک لیگ متشکل از چندین تیم است که هرکدام فهرستی از بازیکنان دارند. فصل جدیدی در شرف شروع است و آنها باید یک سیستم فروش بلیت تازه بسازند تا بلیت بازیها را بفروشند. فصل گذشته بلیتها را در ورودی ورزشگاه میفروختند، اما محبوبیت لیگ بهشدت بالا رفته است و تصمیم گرفتهاند امسال برای پاسخ به تقاضای بیشتر، بلیتها را بهصورت آنلاین بفروشند.
لیگ با شما تماس گرفته و از شما خواسته است سیستمی بسازید که فروش بلیت را مدیریت کند.
اول باید یک سیستم فروش بلیت بسازید تا فروش بلیت را مدیریت کنید. سیستم فروش بلیت باید بگوید چند بلیت برای یک بازی موجود است.
برای هر بازی باید نمونهای از کلاسی به اسم TicketSystem ساخته شود.
حالت مقداردهیشده باید اطلاعات زیر را نگه دارد:
حالت مقداردهیشده را از آرگومانهایی بسازید که تعداد بلیتهای موجود و ورزشگاهی که مسابقه در آن انجام میشود را مشخص میکنند.
حالت مقداردهیشده باید از متغیرهای نمونهای @tickets_available و @stadium تشکیل شده باشد.
اینها باید بهترتیب شامل آرگومان اول و دوم دادهشده باشند.
TicketSystem.new(100, "Bellebrook")
# => #<TicketSystem:0x10f0b8 @tickets_available=100, @stadium="Bellebrook">
اول باید متدی بسازید که تعداد بلیتهای موجود برای یک بازی مشخص را برمیگرداند.
یک ماژول به اسم TicketingReservation بالای کلاسی که قبلاً تعریف شده است تعریف کنید.
این ماژول باید در کلاس TicketSystem گنجانده شود.
درون ماژول، متدی به اسم tickets_available تعریف کنید.
این متد باید تعداد بلیتهای موجود را برگرداند.
ticket_system = TicketSystem.new(100)
ticket_system.tickets_available
#=> 100
باید متدی بسازید که بررسی کند آیا برای یک بازی مشخص بلیت موجود است یا نه. بازی باید ۱۰۰ بلیت ذخیره داشته باشد. هدف این است که همیشه برای کسانی که در ورودی ورزشگاه بلیت میخرند، بلیت موجود باشد.
درون ماژول TicketingReservation متدی به اسم order_ticket? تعریف کنید.
متد باید اگر حداقل ۱۰۰ بلیت موجود باشد true و در غیر این صورت false را برگرداند.
اگر حداقل ۱۰۰ بلیت موجود باشد، متد باید تعداد بلیتهای موجود را هم ۱ واحد کاهش دهد.
ticket_system = TicketSystem.new(100)
ticket_system.order_ticket?
#=> true
سیستم فروش بلیت باید پیامهایی داشته باشد که درکشان برای کاربران آسان باشد. و پیامها باید صمیمی به نظر برسند، بنابراین باید اسم کاربر را در خود داشته باشند.
اگر خرید بلیت موفق بوده باشد، کاربر باید پیامی دریافت کند که به او بگوید خرید موفق بوده، شمارهی بلیتش چیست و بازی در کدام ورزشگاه انجام میشود. شمارهی بلیت باید تعداد بلیتهای موجود پیش از سفارش باشد.
اگر خرید موفق بوده باشد، پیام باید به این شکل باشد: {name}, your purchase was successful, your ticket number is #{ticket_number}, and the game is played at the {stadium_name} stadium..
اگر خرید ناموفق بوده باشد، پیام باید به این شکل باشد: {name}, your purchase was unsuccessful, there are not enough tickets available..
درون ماژول TicketingReservation, متدی به اسم order_message تعریف کنید که آرگومانی به اسم name میگیرد و اسم خریدار را در خود دارد.
متد باید رشتهای حاوی پیام برگرداند.
ticket_system = TicketSystem.new(100, "Bellebrook")
ticket_system.order_message("John")
#=> "John, your purchase was successful, your ticket number is #100, and the game is played at the Bellebrook stadium."