مقدمه
به فصل پنجم و دنیای شگفتانگیز برنامهنویسی شیءگرا (Object-Oriented Programming -
OOP) خوش آمدید! تا به اینجا با ساختارهای پایهای زبان C# آشنا شدهایم.
اکنون زمان آن رسیده که یاد بگیریم چگونه با استفاده از کلاسها، مفاهیم دنیای واقعی را در قالب
کدهای ساختاریافته و قابل مدیریت مدلسازی کنیم. کلاس (Class) مهمترین و
بنیادیترین مفهوم در OOP و قلب تپندهی زبان C# است. یک کلاس در واقع یک نقشه
یا بلوپرینت برای ساختن اشیاء (Objects) است. در این درس، با نحوهی
تعریف کلاس، ایجاد اشیاء از روی آن و نقش حیاتی سازندهها (Constructors) در
مقداردهی اولیه این اشیاء آشنا خواهیم شد.
تعریف یک کلاس
یک کلاس، دادهها (اطلاعات) و رفتارها (عملیات) مرتبط با یک مفهوم را در یک واحد منسجم به نام
شیء (Object) کپسوله میکند. برای تعریف یک کلاس از کلمهی کلیدی class استفاده میکنیم. بیایید یک مفهوم ساده مانند "اتومبیل" را به
عنوان یک کلاس مدلسازی کنیم.
فیلدها و متدها: داده و رفتار
یک کلاس معمولاً از دو جزء اصلی تشکیل میشود:
- فیلدها (Fields): متغیرهایی هستند که درون کلاس تعریف میشوند و وضعیت
(state) یا دادههای یک شیء را نگهداری میکنند. برای مثال، مدل، رنگ و سال ساخت
یک اتومبیل فیلدهای آن هستند.
- متدها (Methods): توابعی هستند که درون کلاس تعریف میشوند و رفتار
(behavior) یک شیء را مشخص میکنند. برای مثال، روشن کردن موتور یا شتاب گرفتن،
متدهای کلاس اتومبیل هستند.
Program.cs
public class Car
{
public string Model;
public string Color;
public int Year;
public void StartEngine()
{
Console.WriteLine($"The {Model} engine starts. Vroom!");
}
}
در کد بالا، یک کلاس به نام Car تعریف کردهایم. این کلاس سه فیلد عمومی (Model، Color و
Year) برای ذخیرهی اطلاعات اتومبیل و یک متد عمومی (StartEngine) برای تعریف یکی از رفتارهای
آن دارد. در حال حاضر فیلدها را public تعریف کردهایم، اما در درسهای آینده خواهیم دید که
بهترین روش، خصوصی (private) کردن فیلدها و کنترل دسترسی به آنهاست (مفهوم Encapsulation).
ایجاد اشیاء (نمونهسازی)
کلاس به تنهایی یک نقشه است و تا زمانی که از روی آن یک شیء واقعی نسازیم، کاربردی ندارد. فرآیند
ساختن یک شیء از روی یک کلاس را نمونهسازی (Instantiation) مینامند. برای این
کار از کلمهی کلیدی new استفاده میکنیم.
Program.cs
Car myCar = new Car();
myCar.Model = "Tesla Model S";
myCar.Color = "Red";
myCar.Year = 2024;
Console.WriteLine($"My car is a {myCar.Color} {myCar.Year} {myCar.Model}.");
myCar.StartEngine();
در این کد، myCar یک متغیر از نوع Car است. به یاد بیاورید که کلاسها از نوع ارجاعی هستند،
بنابراین myCar ارجاعی به یک شیء Car است که در حافظهی Heap ایجاد شده. پس از ایجاد شیء،
میتوانیم با استفاده از عملگر نقطه به فیلدها و متدهای عمومی آن دسترسی پیدا کرده و مقادیر
فیلدها را تنظیم یا متدهای آن را فراخوانی کنیم.
سازندهها (Constructors)
مقداردهی تکتک فیلدهای یک شیء پس از ایجاد آن میتواند خستهکننده و مستعد خطا باشد. مهمتر از آن،
ممکن است بخواهیم تضمین کنیم که یک شیء به محض ایجاد شدن، در یک وضعیت معتبر و کامل قرار دارد.
اینجاست که سازندهها وارد عمل میشوند.
نقش سازندهها
سازنده یک متد ویژه درون کلاس است که نام آن دقیقاً با نام کلاس یکسان است و هیچ مقدار بازگشتی (حتی
void) ندارد. وظیفهی اصلی سازنده، مقداردهی اولیه فیلدهای
شیء در لحظهی ایجاد آن است. سازنده به طور خودکار هنگام استفاده از کلمهی کلیدی new فراخوانی میشود.
سازندهی پیشفرض و سفارشی
اگر شما هیچ سازندهای برای کلاس خود تعریف نکنید، کامپایلر C# یک سازندهی عمومی و بدون
پارامتر به نام سازندهی پیشفرض (Default Constructor) برای شما ایجاد میکند.
این سازنده فیلدهای کلاس را با مقادیر پیشفرضشان (صفر برای اعداد، null برای ارجاعیها و false
برای bool) مقداردهی میکند. این همان سازندهای بود که در مثال قبلی برای new Car() فراخوانی
شد.
اما معمولاً ما میخواهیم کنترل بیشتری روی فرآیند ایجاد شیء داشته باشیم. برای این کار، یک
سازندهی سفارشی تعریف میکنیم.
Program.cs
public class Car
{
public string Model;
public int Year;
public Car(string model, int year)
{
Model = model;
Year = year;
}
}
Car myCar = new Car("Ford Mustang", 1969);
Console.WriteLine($"Created a {myCar.Year} {myCar.Model}.");
نکتهی بسیار مهم: به محض اینکه شما حتی یک سازنده (با یا بدون پارامتر) برای کلاس
خود تعریف کنید، کامپایلر دیگر سازندهی پیشفرض را برای شما ایجاد نمیکند.
بنابراین، پس از تعریف سازندهی بالا، دیگر نمیتوانید یک Car با new Car() بسازید و این کار
منجر به خطای کامپایل میشود.
کلمهی کلیدی this
کلمهی کلیدی this یک ارجاع به نمونهی فعلی کلاس
است. این کلمه کلیدی کاربردهای مختلفی دارد، اما رایجترین کاربرد آن برای رفع ابهام بین نام
پارامترهای یک متد (بهویژه سازنده) و نام فیلدهای کلاس است.
Program.cs
public class Person
{
private string name;
private int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Introduce()
{
Console.WriteLine($"Hi, I am {this.name} and I am {this.age} years old.");
}
}
در سازندهی کلاس Person، نام پارامترها (name و age) با نام فیلدهای کلاس یکسان است. برای
اینکه به کامپایلر بگوییم منظور ما فیلد کلاس است، از this.name و this.age استفاده میکنیم.
این یک قرارداد رایج و بسیار خوانا در برنامهنویسی C# است و به ما اجازه میدهد از
نامهای توصیفی و یکسان برای پارامترها و فیلدها استفاده کنیم.