آموزش کلاسها و اشیاء از مهمترین و اصلیترین مفاهیم در برنامهنویسی شیگرا (Object-Oriented Programming) محسوب میشوند که زبان کاتلین نیز بر اساس آنها ساخته شده است. در این سبک برنامهنویسی، بهجای تمرکز بر توابع و رویهها، از اشیا که دارای ویژگیها و رفتارها هستند، استفاده میشود. در ادامه به بررسی کامل مفهوم کلاس و شی و نحوه استفاده از آنها در زبان کاتلین خواهیم پرداخت.
تعریف کلاسها و اشیاء (Classes & Objects)
تعریف کلاس (Class)
کلاس در واقع الگو یا قالبی است که برای ساخت اشیا مورد استفاده قرار میگیرد. کلاس شامل ویژگیها (متغیرها) و متدها (توابع) است که توصیفکننده یک شیء میباشند. با تعریف یک کلاس، میتوان نمونههایی از آن را ساخت که هر کدام یک شی مستقل با ویژگیها و رفتارهای مختص به خود هستند.
ایجاد کلاس در کاتلین
در کاتلین، میتوان بهسادگی با استفاده از کلمه کلیدی class یک کلاس ایجاد کرد. به عنوان مثال، فرض کنید میخواهیم کلاسی به نام Person بسازیم که اطلاعات یک فرد را نگهداری کند، مثلاً نام و سن:
class Person(val name: String, var age: Int) {
// یک متد برای نمایش اطلاعات شخص
fun displayInfo() {
println("Name: $name, Age: $age")
}
}
Person یک کلاس است که دو ویژگی name و age دارد.
متد displayInfo، برای نمایش اطلاعات شخص است.
تعریف شی (Object)
شی یک نمونه (Instance) از یک کلاس است. زمانی که یک شیء از یک کلاس ایجاد میکنید، در واقع به آن قالب دادههای واقعی میدهید و آن را به یک موجودیت زنده و قابل استفاده تبدیل میکنید. هر شیء از روی یک کلاس دارای ویژگیها و رفتارهای تعریفشده در آن کلاس است.
ساختن شی از یک کلاس
برای ایجاد یک شی از کلاس Person، بهسادگی میتوانیم به صورت زیر عمل کنیم:
fun main() {
val person1 = Person("Ali", 25)
person1.displayInfo() // خروجی: Name: Ali, Age: 25
val person2 = Person("Sara", 30)
person2.displayInfo() // خروجی: Name: Sara, Age: 30
}
در این مثال:
person1 و person2 دو شیء متفاوت از کلاس Person هستند.
هر کدام دارای دادههای مختص به خود هستند، اما از یک کلاس ساخته شدهاند و به همین دلیل میتوانند از متدهای تعریفشده در آن کلاس استفاده کنند.
تفاوت بین کلاس و شی
کلاس، فقط یک قالب یا نقشه است که ویژگیها و رفتارهای مشترک را تعریف میکند. از طرف دیگر، شی، نمونهای از یک کلاس است که با دادههای واقعی پر شده است و میتواند به صورت مستقل در برنامه عمل کند.
به طور کلی:
کلاس: الگو یا نقشهای برای ایجاد اشیا.
شی: یک نمونه از کلاس که دارای دادههای واقعی است.
اصول برنامهنویسی شیگرا
کلاسها و اشیا در برنامهنویسی شیگرا با چهار اصل اساسی کار میکنند:
کپسولهسازی (Encapsulation): اطلاعات و متدهای مرتبط با یک شی در داخل کلاس آن قرار داده میشوند. این کار به پنهانسازی دادهها کمک میکند و فقط متدهای مشخص اجازه دسترسی به دادههای داخلی را دارند.
وراثت (Inheritance): با استفاده از وراثت، میتوان کلاسی جدید ایجاد کرد که ویژگیها و رفتارهای کلاس دیگری را به ارث ببرد. این کار باعث میشود از کدهای تکراری اجتناب شود.
چندریختی (Polymorphism): به این معناست که متدها و اشیا میتوانند به شکلهای مختلف عمل کنند. با استفاده از چندریختی، میتوان یک متد را برای کلاسهای مختلف پیادهسازی کرد و هر کلاس رفتار متفاوتی از خود نشان دهد.
تجزیه (Abstraction): در این اصل، فقط ویژگیها و متدهای مهم در دسترس قرار میگیرند و جزئیات پیچیده پنهان میشوند.
مثال جامع: یک کلاس Car در کاتلین
فرض کنید میخواهیم کلاسی به نام Car ایجاد کنیم که دارای ویژگیهایی مانند رنگ، مدل، و سرعت باشد و بتواند رفتارهایی مانند حرکت کردن و توقف را انجام دهد.
class Car(val color: String, val model: String, var speed: Int) {
fun drive() {
println("The $model is driving at $speed km/h.")
}
fun stop() {
println("The $model has stopped.")
}
}
fun main() {
val car1 = Car("Red", "Toyota", 120)
val car2 = Car("Blue", "Ford", 100)
car1.drive() // خروجی: The Toyota is driving at 120 km/h.
car2.stop() // خروجی: The Ford has stopped.
}
در این مثال:
Car یک کلاس است که دارای ویژگیهای color, model، و speed است.
متدهای drive و stop رفتارهای کلاس را توصیف میکنند.
car1 و car2 دو شیء مستقل از کلاس Car هستند که با دادههای واقعی مقداردهی شدهاند و میتوانند به صورت مستقل عمل کنند.
مزایای استفاده از کلاسها و اشیا در برنامهنویسی شیگرا
استفاده از کلاسها و اشیا به دلایل زیر در برنامهنویسی مفید است:
ساختاردهی بهتر برنامهها: با استفاده از کلاسها، میتوان دادهها و رفتارهای مرتبط را در کنار هم قرار داد و ساختاری منظم ایجاد کرد.
کاهش تکرار کد (اصل DRY): به کمک کلاسها، میتوان از تکرار کدهای مشابه جلوگیری کرد. با یکبار تعریف یک کلاس، میتوان از آن در بخشهای مختلف برنامه استفاده کرد.
قابلیت استفاده مجدد: با استفاده از اصول وراثت و چندریختی، میتوان از کدهای نوشتهشده در کلاسهای دیگر به راحتی استفاده کرد.
قابلیت نگهداری و توسعه آسانتر: ساختار شیگرا باعث میشود تغییرات و بهبودها در کد آسانتر و مؤثرتر اعمال شوند.
آموزش کلاسهای داده (Data Classes)
برای ایجاد یک کلاس در کاتلین، از کلمه کلیدی `class` استفاده میکنیم و پس از آن، نام کلاس را مینویسیم. در سادهترین حالت، میتوان یک کلاس را بدون هیچ ویژگی یا متدی تعریف کرد. اما معمولاً کلاسها شامل ویژگیها و متدها هستند تا بتوانند دادهها و رفتارها را توصیف کنند.
تعریف ساده یک کلاس در کاتلین
در این مثال، یک کلاس ساده به نام `Person` تعریف میکنیم:
class Person
در این حالت، `Person` یک کلاس بدون ویژگی و متد است و نمیتواند اطلاعات خاصی را نگهداری کند یا عملکردی داشته باشد.
افزودن سازنده (Constructor) به کلاس
کلاسها معمولاً دارای سازنده هستند که برای مقداردهی اولیه به اشیا استفاده میشود. سازنده در کاتلین میتواند بهسادگی در جلوی نام کلاس تعریف شود. برای مثال، فرض کنید میخواهیم به `Person` دو ویژگی `name` و `age` اضافه کنیم.
class Person(val name: String, var age: Int)
در اینجا:
– `name` و `age` دو ویژگی کلاس `Person` هستند.
– `val` نشاندهنده یک ویژگی غیرقابل تغییر (مشابه متغیر `final` در جاوا) است و `var` نشاندهنده یک ویژگی قابل تغییر.
افزودن متد به کلاس
میتوانیم متدها را برای اضافه کردن رفتارها به کلاس تعریف کنیم. به عنوان مثال، متدی به نام `greet` اضافه میکنیم که یک پیام خوشامدگویی را چاپ میکند.
class Person(val name: String, var age: Int) {
fun greet() {
println("Hello, my name is $name and I am $age years old.")
}
}
استفاده از کلاس و ایجاد شی
برای استفاده از کلاس و ایجاد یک **شیء**، به سادگی یک نمونه از کلاس ایجاد میکنیم. این کار با استفاده از سازنده کلاس انجام میشود.
class Person(val name: String, var age: Int) {
fun greet() {
println("Hello, my name is $name and I am $age years old.")
}
}
توضیح بیشتر
ساخت یک شیء: `val person1 = Person(“Ali”, 25)` یک شیء جدید به نام `person1` از کلاس `Person` ایجاد میکند که ویژگی `name` آن “Ali” و ویژگی `age` آن 25 است.
فراخوانی متد: با استفاده از `person1.greet()`، متد `greet` برای شیء `person1` فراخوانی میشود که پیام خوشامدگویی را چاپ میکند.
نتیجه
در کاتلین، ایجاد یک کلاس به سادگی با استفاده از کلمه کلیدی `class` و مشخص کردن نام کلاس امکانپذیر است. کلاسها میتوانند شامل ویژگیها، متدها، و حتی سازندههای مختلف باشند که به اشیا اجازه میدهد دادهها و رفتارهای متنوعی را نگهداری و ارائه کنند.
توابع عضو (Member Functions)
در کاتلین، میتوان توابع (که به آنها متد نیز گفته میشود) را داخل یک کلاستعریف کرد تا عملیاتها و رفتارهای مختلفی را برای اشیا آن کلاس انجام دهند. این توابع به شما اجازه میدهند که قابلیتهای بیشتری را به اشیا اضافه کنید و از کپسولهسازی استفاده کنید تا رفتارهای مرتبط با دادههای آن شیء را درون همان کلاس نگه دارید.
تعریف توابع داخل کلاس
برای تعریف توابع داخل یک کلاس در کاتلین، از همان ساختار تعریف توابع معمولی استفاده میشود، اما این توابع درون بدنه کلاس قرار میگیرند. به عنوان مثال، فرض کنید کلاسی به نام `Calculator` داریم که توابعی برای انجام عملیات جمع، تفریق، ضرب و تقسیم ارائه میدهد.
class Calculator {
// تابع برای جمع دو عدد
fun add(a: Int, b: Int): Int {
return a + b
}
// تابع برای تفریق دو عدد
fun subtract(a: Int, b: Int): Int {
return a - b
}
// تابع برای ضرب دو عدد
fun multiply(a: Int, b: Int): Int {
return a * b
}
// تابع برای تقسیم دو عدد
fun divide(a: Int, b: Int): Int {
if (b != 0) {
return a / b
} else {
println("Division by zero is not allowed")
return 0
}
}
}
استفاده از توابع کلاس
پس از تعریف توابع داخل کلاس، میتوانیم از آنها با ساختن یک **شیء** از کلاس استفاده کنیم. به عنوان مثال، در اینجا یک نمونه از کلاس `Calculator` میسازیم و توابع آن را فراخوانی میکنیم:
fun main() {
val calculator = Calculator() // ایجاد شیء جدید از کلاس Calculator
// استفاده از توابع کلاس
println("Addition: ${calculator.add(10, 5)}") // خروجی: Addition: 15
println("Subtraction: ${calculator.subtract(10, 5)}") // خروجی: Subtraction: 5
println("Multiplication: ${calculator.multiply(10, 5)}") // خروجی: Multiplication: 50
println("Division: ${calculator.divide(10, 5)}") // خروجی: Division: 2
}
توابع با دسترسی به ویژگیهای کلاس
توابع داخل یک کلاس میتوانند به **ویژگیهای** آن کلاس نیز دسترسی داشته باشند. برای مثال، اگر بخواهیم کلاسی به نام `Person` بسازیم که شامل ویژگیهای `name` و `age` باشد و تابعی به نام `introduce` داشته باشد که این ویژگیها را چاپ کند، به شکل زیر عمل میکنیم:
class Person(val name: String, var age: Int) {
// تابعی که ویژگیها را نمایش میدهد
fun introduce() {
println("Hello, my name is $name and I am $age years old.")
}
}
fun main() {
val person = Person("Sara", 28)
person.introduce() // خروجی: Hello, my name is Sara and I am 28 years old.
}
توابع Member و Extension
در کاتلین، میتوان علاوه بر توابع Member که داخل کلاس تعریف میشوند، از **توابع Extension** نیز استفاده کرد. توابع Extension به شما اجازه میدهند تا بدون نیاز به تغییر در کد کلاس اصلی، به آن کلاس توابع اضافه کنید.
برای مثال، تابعی به نام `doubleAge` به کلاس `Person` اضافه میکنیم که سن فرد را دو برابر میکند، بدون اینکه کلاس اصلی را تغییر دهیم:
fun Person.doubleAge(): Int {
return this.age * 2
}
fun main() {
val person = Person("Sara", 28)
println("Double Age: ${person.doubleAge()}") // خروجی: Double Age: 56
}
نتیجهگیری
توابع در کلاسها به شما این امکان را میدهند که رفتارهایی مرتبط با دادهها و ویژگیهای آن کلاس را درون آن کلاس تعریف کنید و از این رفتارها برای ایجاد برنامهای ساختاریافته و قابل توسعه استفاده کنید. همچنین، کاتلین با پشتیبانی از **توابع Extension** امکان افزودن توابع به کلاسهای موجود را بدون تغییر در ساختار آنها فراهم میکند.
توابع و خواص کلاس (Class Properties)
در برنامهنویسی شیگرا، کلاسها و اشیادو مفهوم کلیدی هستند. در ادامه، این مفاهیم و تفاوتهای آنها را با یک مثال ساده توضیح میدهم.
کلاس (Class)
کلاس، الگوی اولیه یا نقشهای برای ساخت اشیا است. وقتی یک کلاس تعریف میکنید، در واقع دارید ویژگیها (متغیرها) و رفتارها (توابع) را برای نوع خاصی از اشیا تعریف میکنید.
به عنوان مثال، فرض کنید میخواهید یک کلاس به نام `Car` بسازید که ویژگیهایی مثل رنگ، مدل، و سرعت داشته باشد و رفتارهایی مثل حرکت و توقف را شامل شود:
class Car(val color: String, val model: String, var speed: Int) {
fun drive() {
println("The $model is driving.")
}
fun stop() {
println("The $model has stopped.")
}
}
در اینجا، `Car` یک کلاس است که شامل ویژگیهای `color`, `model`, و `speed` و همچنین دو متد `drive()` و `stop()` است.
شی (Object)
شی، نمونهای از یک کلاس است. هنگامی که از روی یک کلاس شیء میسازید، در واقع به آن کلاس، دادههای واقعی میدهید و آن را به یک موجودیت مستقل تبدیل میکنید که میتواند در برنامه استفاده شود.
مثال: ساختن دو شیء از کلاس `Car` با مقادیر متفاوت:
fun main() {
val car1 = Car("Red", "Toyota", 120)
val car2 = Car("Blue", "Ford", 100)
car1.drive() // خروجی: The Toyota is driving.
car2.stop() // خروجی: The Ford has stopped.
}
در اینجا، `car1` و `car2` دو شیء مستقل از کلاس `Car` هستند که میتوانند رفتارهای خود را انجام دهند.
تفاوت بین کلاس و شی:
1. کلاس، فقط یک قالب یا نقشه است و تا زمانی که نمونهسازی نشده، هیچ دادهای ندارد.
2. شی، نمونهای از کلاس است که به آن دادههای واقعی اختصاص داده شده و میتواند در برنامه استفاده شود.
کلاسهای اولیه (Primary & Secondary Constructors)
در زبان کاتلین، سازنده روشی برای مقداردهی اولیه به ویژگیها (پراپرتیها) در هنگام ساخت یک شیء از یک کلاس است. برخلاف سایر زبانها، کاتلین از دو نوع سازنده استفاده میکند:سازنده اولیه (Primary Constructor) وسازنده ثانویه (Secondary Constructor). هر کدام از این سازندهها کاربرد خاصی دارند و بسته به نیاز برنامهنویس، میتوان از یکی یا هر دو استفاده کرد.
سازنده اولیه (Primary Constructor)
سازنده اولیه بهعنوان بخش اصلی کلاس در کاتلین شناخته میشود و مستقیماً در کنار نام کلاس تعریف میشود. این سازنده فقط برای مقداردهی ویژگیهای کلاس به کار میرود و نمیتواند منطق پیچیدهای داشته باشد.
برای تعریف سازنده اولیه، پارامترهای آن را داخل پرانتز پس از نام کلاس قرار میدهیم. ویژگیهای کلاس را با استفاده از کلمات کلیدی `val` یا `var` در سازنده تعریف میکنیم.
مثال سازنده اولیه
در این مثال، کلاسی به نام `Person` داریم که دارای ویژگیهای `name` و `age` است. این ویژگیها توسط سازنده اولیه مقداردهی میشوند.
class Person(val name: String, var age: Int) {
// تابعی برای نمایش اطلاعات شخص
fun displayInfo() {
println("Name: $name, Age: $age")
}
}
fun main() {
val person = Person("Sara", 28)
person.displayInfo() // خروجی: Name: Sara, Age: 28
}
در اینجا:
– `name` و `age` ویژگیهای کلاس هستند که با استفاده از سازنده اولیه مقداردهی میشوند.
– سازنده اولیه مستقیماً پس از نام کلاس و با پارامترهای مورد نظر تعریف شده است.
سازنده ثانویه (Secondary Constructor)
سازنده ثانویه در کاتلین برای افزودن منطق اضافی یا انجام عملیاتهای پیچیدهتر هنگام مقداردهی اولیه استفاده میشود. سازندههای ثانویه معمولاً زمانی استفاده میشوند که نیاز به چند سازنده با منطق مختلف باشد یا بخواهیم پردازش بیشتری در هنگام مقداردهی انجام دهیم.
در سازنده ثانویه، از کلمه کلیدی `constructor` استفاده میشود و سازندهها میتوانند داخل بدنه کلاس قرار بگیرند. همچنین اگر سازنده اولیه وجود داشته باشد، سازنده ثانویه باید آن را فراخوانی کند تا مقداردهی اولیه انجام شود. برای فراخوانی سازنده اولیه از کلمه کلیدی `this` استفاده میکنیم.
مثال سازنده ثانویه
در این مثال، سازنده اولیه `Person` تنها ویژگی `name` را مقداردهی میکند. سازنده ثانویه هم ویژگی `name` و هم ویژگی `age` را مقداردهی میکند.
class Person(val name: String) {
var age: Int = 0
// سازنده ثانویه برای مقداردهی نام و سن
constructor(name: String, age: Int) : this(name) {
this.age = age
}
fun displayInfo() {
println("Name: $name, Age: $age")
}
}
fun main() {
val person1 = Person("Ali") // استفاده از سازنده اولیه
person1.displayInfo() // خروجی: Name: Ali, Age: 0
val person2 = Person("Sara", 28) // استفاده از سازنده ثانویه
person2.displayInfo() // خروجی: Name: Sara, Age: 28
}
در این مثال:
– سازنده اولیه فقط ویژگی `name` را مقداردهی میکند.
– سازنده ثانویه علاوه بر `name`، ویژگی `age` را نیز مقداردهی میکند. این سازنده با استفاده از `this(name)`، سازنده اولیه را فراخوانی میکند.
– این قابلیت به شما امکان میدهد تا برای کلاس، سازندههای مختلف با وظایف و منطق متفاوت تعریف کنید.
نکات مهم در مورد سازندهها در کاتلین
1. سازنده اولیه همیشه به عنوان سازنده اصلی شناخته میشود و برای مقداردهی اولیه ویژگیها استفاده میشود.
2. سازنده ثانویه تنها در صورتی نیاز است که به منطق اضافه در مقداردهی اولیه نیاز داشته باشید.
3. اگر کلاس دارای سازنده اولیه باشد، **سازنده ثانویه باید سازنده اولیه را فراخوانی کند**.
نتیجهگیری
در کاتلین، سازنده اولیهبه سادگی برای مقداردهی اولیه ویژگیهای کلاس استفاده میشود و در کنار نام کلاس تعریف میشود. اما در موارد خاص، میتوان از سازنده ثانویه برای افزودن منطق اضافی به مقداردهی اولیه استفاده کرد.
