کاوش در کلاس های انتزاعی کاتلین و انواع کلاس های تخصصی: راهنمای مفاهیم برنامه نویسی شی گرا.

در این مقاله قصد داریم به دو مفهوم مهم در توسعه اندروید مدرن بپردازیم.
در پایان این مقاله، هدف ما این خواهد بود که به موارد زیر بپردازیم:
1. کلاس های انتزاعی
2. انواع کلاس های ویژه در کاتلین
I. کلاس های چکیده
- کلاس های انتزاعی را می توان ترکیبی از یک کلاس باز و یک رابط در نظر گرفت.
- یک کلاس انتزاعی با استفاده از کلمه کلیدی انتزاعی در جلوی کلاس اعلام می شود.
abstract
class
className
{}
- کلاس های انتزاعی می توانند دارای ویژگی های عضو انتزاعی و غیرانتزاعی در یک کلاس انتزاعی باشند. این ویژگی ها با اصلاح کننده انتزاعی مشخص شده اند و مانند شکل زیر بدنه ای ندارند.
abstract class className(val x : String) //non-abstract property
{
abstract var y : Int //Abstract property
abstract fun method () //Abstract property
fun method () //non-abstract method property
{
println("Non abstract function")
}
}
- از کلاس های انتزاعی نمی توان برای ایجاد اشیا استفاده کرد. با این حال، شما می توانید زیر کلاس ها را از آنها به ارث ببرید، اما آنها باید نادیده گرفته شوند.
- مزیت کلیدی کلاس های انتزاعی این است که می توانند متدهای غیر باز و ویژگی های غیرانتزاعی داشته باشند.
abstract class Employee (val name : String,val experience : Int){
//abstract property
abstract var salary : Double
abstract fun dateOfBirth(date : String)
//non-abstract property
fun employeeDetails() {
println("Name of the employee : $name")
println("Experience in years : $experience")
println("Annual salary : $salary")
}
}
//derived class
class Engineer (name: String, experience: Int): Employee(name, experience) {
override var salary = 5000.00
override fun dateOfBirth(date : String){
println("Date of Birth is: $date")
}
}
fun main () {
val eng = Engineer("Praveen",2)
eng.employeeDetails()
eng.dateOfBirth("02 December 1994")
}
- کلاس های انتزاعی عمدتاً زمانی استفاده می شوند که بخواهید مجموعه ای از عملیات عمومی را برای چندین کلاس مشخص کنید. یک عضو انتزاعی از کلاس انتزاعی را می توان در تمام کلاس های مشتق شده بازنویسی کرد.
- در کلاس زیر، تابع cal را در سه کلاس مشتق شده از ماشین حساب لغو می کنیم.
abstract class Calculator {
abstract fun cal (firstNum : Int, secondNum : Int): Int
}
//Addition of two numbers
class Add : Calculator () {
override fun cal (firstNum : Int, secondNum : Int) : Int{
return firstNum + secondNum
}
}
//Division of two numbers
class Divide : Calculator () {
override fun cal (firstNum : Int, secondNum : Int) : Int{
return firstNum / secondNum
}
}
//Multiplication of two numbers
class Multiply : Calculator () {
override fun cal (firstNum : Int, secondNum : Int) : Int{
return firstNum * secondNum
}
}
//Subtraction of two numbers
class Subtract : Calculator () {
override fun cal (firstNum : Int, secondNum : Int) : Int{
return firstNum - secondNum
}
}
fun main () {
var add : Calculator = Add()
var add1 = add.cal(4,3)
println("Addition of two numbers $add1")
var subtract : Calculator = Subtract()
var add2 = subtract.cal(4,3)
println("Subtraction of two numbers $add2")
var multiply : Calculator = Multiply()
var add3 = multiply.cal(4,3)
println("Multiplication of two numbers $add3")
var divide : Calculator = Divide()
var add4 = divide.cal(24,3)
println("Division of two numbers $add4")
}
- در کاتلین، میتوانیم تابع عضو باز غیرانتزاعی کلاس باز را با استفاده از عبارت لغو کنیم
override keyword
به دنبال آن یک چکیده در کلاس انتزاعی.
open class vertebrates {
open fun Backbone () {
println("All vertebrates have a backbone")
}
}
abstract class Animal : vertebrates () {
override abstract fun Backbone ()
}
class Birds : Animal () {
override fun Backbone () {
println("Birds have a backbone")
}
}
fun main () {
val animals = vertebrates ()
animals.Backbone()
val birds = Birds()
birds.Backbone()
}
II. کلاس های خاص
- کلاس های مختلفی وجود دارد که هر کدام یک هدف اختصاصی دارند. این کلاس ها عبارتند از:
- کلاس های داده
- کلاس های Enum
- کلاس های استثنایی
- کلاس های مهر و موم شده
- کلاس های حاشیه نویسی
1. کلاس های داده
- کلاس های داده نوع خاصی از کلاس هستند که به عنوان دارنده داده ها خدمت می کنند. آنها به مقایسه، نمایش، خواندن و تغییر آسان این داده ها کمک می کنند.
- مقادیر پایه مانند رشته ها را می توان با استفاده از علامت تساوی دوگانه مقایسه کرد.
class superCars (val name : String,val year : Int)
fun main () {
var car1 = superCars("volvo",2020)
var car2 = superCars("BMW" ,2021)
var car3 = superCars("volvo",2020)
var car4 = superCars("Benz",2019)
println(car1 == car2)//false
println(car1 == car1)//true
println(car3 == car4)//false
}
- اگر مقادیر یکسان باشند، نتیجه درست است و اگر مقادیر متفاوت باشند، نادرست است.
- هنگامی که از دستور نقطه در تابع اصلی خود برای فراخوانی خصوصیات کلاس مانند شکل زیر استفاده می کنیم.
class superCars (val name : String,val Modelyear : Int)
fun main () {
var car1 = superCars("volvo",2020)
var car2 = superCars("BMW" ,2021)
var car3 = superCars("volvo",2020)
var car4 = superCars("Benz",2019)
println(car1.name)
println(car1.Modelyear)
println(car4.name)
println(car4.Modelyear)
}
خروجی کد خواهد شد volvo
2020
و Benz
2019
- وقتی نمونههای کلاس خود را بدون تعیین دادههای کلمه کلیدی فراخوانی میکنیم، خروجی محل ذخیرهسازی نمونه در کلاس را نشان میدهد.
class superCars (val name : String,val Modelyear : Int)
fun main () {
var car1 = superCars("volvo",2020)
var car2 = superCars("BMW" ,2021)
var car3 = superCars("volvo",2020)
var car4 = superCars("Benz",2019)
println(car1)//superCars@37f8bb67
println(car2)//superCars@439f5b3d
}
خروجی کد بالا می باشد superCars@37f8bb67
برای car1 و superCars@439f5b3d
به ترتیب برای car2.
- زمانی که ما تخصص داریم
keyword data
قبل از کلاس خروجی کد تغییر می کند. این به این دلیل است که رفتار برابری تغییر کرده است.
data class superCars (val name : String,val Modelyear : Int)
fun main () {
var car1 = superCars("volvo",2020)
var car2 = superCars("BMW" ,2021)
var car3 = superCars("volvo",2020)
var car4 = superCars("Benz",2019)
println(car1)
println(car2)
}
- کلاس های داده دارای الف هستند
copy method
که یک کپی از یک شی ایجاد می کند. این به شما امکان می دهد مشخص کنید که چه تغییراتی را می خواهید در یک شی ایجاد کنید.
data class Person(val firstName: String, val familyName:String) {
var age = 0
}
fun main() {
val person1 = Person("John", "Doe").apply { age = 25 }
val(firstName,familyName) = person1
println(person1.copy(familyName = "Maye"))
}
- شما از اصلاحکنندههای داده برای کلاسهایی استفاده میکنید که برای نمایش دستهای از دادهها استفاده میشوند.
جفت و سه گانه
- این یک کلاس داده با دو ویژگی سازنده است، شما نیازی به تعریف آن ندارید، زیرا با Kotlin توزیع می شود.
- جفت کردن برای نگه داشتن دو مقدار در خواص اول و دوم استفاده می شود.
- شما می توانید استفاده کنید
first
وsecond
خواص هنگام کار با جفت و سه گانه.
fun main () {
val fruits = Pair ("orange","Banana")
//Using the first property
println(fruits.first)
//Using the second property
println(fruits.second)
}
- ما میتوانیم استفاده کنیم
to function
بین دو مقدار با استفاده از ویژگی جفت.
fun main () {
val Pair = 10 to "A"
//Using the first property
println(Pair.first)
//Using the second property
println(Pair.second)
}
- سه گانه برای حفظ سه مقدار در خواص اول، دوم و سوم استفاده می شود.
fun main () {
val pair = Triple("Daniel",45, 'M')
//Using the first property
println(pair.first)
//Using the second property
println(pair.second)
//Using the third property
println(pair.third)
}
- همچنین می توانیم با استفاده از کد زیر همان خروجی را دریافت کنیم
fun main () {
val pair = Triple("Daniel",45,'M')
val(name,age,gender) = pair
//Getting the first property
println(name)
//Getting the second property
println(age)
//Getting the third property
println(gender)
}
2. کلاس های Enum
- enum نوع تخصصی خود را دارد که نشان می دهد چیزی دارای تعدادی مقادیر ممکن است.
- Enum ها با استفاده از عبارت تعریف می شوند
enum keyword
جلوی یک کلاس
enum class days {
sunday,
monday,
tuesday,
wednesday,
thursday,
friday,
saturday
}
- Enum یک سازنده دارد. ثابت های آنها نمونه هایی از یک کلاس enum هستند. ثابت ها را می توان با ارسال مقادیر خاص به سازنده اولیه مقداردهی کرد.
- ما می توانیم با استفاده از نمونه ای که در تابع اصلی خود ایجاد می کنیم به رنگ موز رسیده دسترسی پیدا کنیم.
enum class bananas (val color : String) {
ripe("yellow"),
unripe("green")
}
fun main () {
val colour = bananas.ripe.color
println(colour)
}
- کلاسهای enum Kotlin دارای برخی ویژگیها و عملکردهای داخلی هستند که میتوانند توسط برنامهنویس استفاده شوند.
- در املاکی که داریم
ordinal
وname
. اینordinal
ویژگی مقدار ترتیبی ثابت را ذخیره می کند که معمولاً یک شاخص مبتنی بر صفر است. اینname
ویژگی نام ثابت را ذخیره می کند. - در روش هایی که داریم
values
وvalueOf
. اینvalues
ویژگی لیستی از تمام ثابت های تعریف شده در کلاس enum را برمی گرداند. - این
valueOf
ویژگی ثابت enum تعریف شده در enum را برمی گرداند و با رشته ورودی مطابقت دارد. اگر ثابت، در enum وجود نداشته باشد، یک غیر قانونیArgumentException پرتاب می شود.
enum class HalfYear {
January,
February,
March,
April,
May,
June
}
fun main () {
for(month in HalfYear.values()){
println("${month.ordinal} = ${month.name}")
}
}
- ما میتوانیم با استفاده از ویژگی valueOf در تابع main به ماه جداگانه از کلاس دسترسی داشته باشیم.
println("${HalfYear.valueOf("April")}")
- کلاسهای Enum را میتوان با عبارت When ترکیب کرد. از آنجایی که کلاسهای enum مقداری را که یک نوع میتواند بگیرد محدود میکند، بنابراین وقتی با عبارت When و تعاریف برای تمام ثابتهای ارائهشده استفاده میشود، نیاز به عبارت else کاملاً حذف میشود.
enum class Planets {
Mercury,
Venus,
Earth,
Mars,
Jupiter,
Saturn,
Uranus
}
fun main() {
for (planet in Planets.values()) {
when (planet) {
Planets.Mercury -> println("The Swift Planet")
Planets.Venus -> println("The Morning and evening star")
Planets.Earth -> println("The Goldilocks Planet")
Planets.Mars -> println("The Red Planet")
Planets.Jupiter -> println("The Gas giant Planet")
Planets.Saturn -> println("The Ringed Planet")
Planets.Uranus -> println("The Ice giant Planet")
}
}
}
- ثابتهای Enum نیز با پیادهسازی توابع خود به همراه نادیده گرفتن توابع انتزاعی کلاس، مانند کلاسهای ناشناس رفتار میکنند.
- مهمترین چیز این است که هر ثابت enum باید نادیده گرفته شود.
enum class seasons (var weather : String) {
Summer ("hot") {
override fun foo () {
println("Hot days of the year")
}
},
Winter ("cold") {
override fun foo (){
println("Cold days of the year")
}
},
Rainny ("rain") {
override fun foo (){
println("Rainny days of the year")
}
};
abstract fun foo ()
}
fun main () {
seasons.Winter.foo()
}
- در کلاسهای enum توابع معمولاً درون شیء همراه تعریف میشوند تا به نمونههای خاصی از کلاس وابسته نباشند.
- با این حال، آنها را می توان بدون اشیاء همراه نیز تعریف کرد.
enum class DAYS(val isWeekend: Boolean = false){
SUNDAY(true),
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY(true);
companion object{
fun today(obj: DAYS): Boolean {
return obj.name.compareTo("SATURDAY") == 0 || obj.name.compareTo("SUNDAY") == 0
}
}
}
fun main(){
for(day in DAYS.values()) {
println("${day.ordinal} = ${day.name} and is weekend ${day.isWeekend}")
}
val today = DAYS.MONDAY;
println("Is today a weekend ${DAYS.today(today)}")
}
3. طبقات استثنایی
- استثناها خطاهایی هستند که در زمان اجرا ایجاد می شوند و جریان اجرای برنامه را مختل می کنند.
- ما دو نوع اجرا داریم.
من. استثنا علامت زده شد – اینها استثناهایی هستند که در زمان کامپایل رخ می دهند، به عنوان مثال IOException.
ii تیک Exception را بردارید – اینها استثناهایی هستند که در زمان اجرا رخ می دهند، به عنوان مثال OutOfBoundException. در kotlin از استثناهای بدون علامت استفاده می کنیم.
- ما چند کلمه کلیدی داریم که به ما کمک می کند تا استثناها را مدیریت کنیم.
من. تلاش كردن – به ما کمک می کند تا استثناها را پیدا کنیم.
ii پرت كردن – اگر استثنا پیدا شود، استثنا را می اندازد.
III. گرفتن – پس از پرتاب آن استثنا را می گیرد و
بدن را اجرا کند
IV سرانجام – همیشه اجرا می شود یا ما می گیریم
استثنا یا نه
- اگر برنامه توسط
exitProcess(int)
یاabsort()
، سپسfinally
اجرا نخواهد شد. - نحو:
try {
// your code
// may throw an exception
}
catch (ex : ExceptionName)
{
// Exception handle code
}
finally
{
//This will execute everytime
//It will execute whether we find an exceptiion or not
}
- می توانیم از نحو بالا برای ایجاد یک کلاس استثنایی برای تقسیم یک عدد بر صفر استفاده کنیم.
fun main () {
try {
divide (10,0)
}
catch (ex : Exception)
{
println(ex.message)
}
}
fun divide (a : Int, b : Int){
if(b == 0)
throw Exception("Divide by Zero")
println("Division is :" +a /b)
}
- می توانیم بلوک نهایی را در کد بالا اضافه کنیم. در زیر در نهایت در هر دو مورد اجرا می شود یا استثنا وجود دارد یا خیر.
fun main()
{
try
{
divide(20, 10)
}
catch (ex : Exception)
{
println(ex.message)
}
finally
{
println("I'm executed")
}
// 2nd try block
try
{
// throw an exception
divide(10, 0)
}
catch (ex : Exception)
{
println(ex.message)
}
finally
{
println("I'm executed")
}
}
fun divide(a : Int, b : Int)
{
if (b == 0)
throw Exception("Divide by zero")
println("Division is :" + a / b)
}
4. کلاس های مهر و موم شده
- یک کلاس مهر و موم شده مجموعه ای از زیر کلاس ها را در آن تعریف می کند. کلاس های مهر و موم شده با محدود کردن انواعی که باید در زمان کامپایل به جای زمان اجرا مطابقت داده شوند، ایمنی نوع را تضمین می کنند.
- اعلان نحو کلاس های مهر و موم شده به شرح زیر است:
sealed class NameOfTheClass
- سازنده کلاس های مهر و موم شده به طور پیش فرض محافظت می شوند. کلاس مهر و موم شده به طور ضمنی انتزاعی است و از این رو نمی توان آن را نمونه کرد.
sealed class DemoClass
fun main () {
var InstanceDemo = Demo ()
}
- کد بالا به دلیل خطای کامپایل اجرا نمی شود زیرا کلاس های مهر و موم شده نمی توانند نمونه سازی شوند.
- تمام زیر کلاس های یک کلاس مهر و موم شده باید در همان فایل kotlin تعریف شوند.
sealed class School {
class Public:School(){
fun display(){
println("They are funded by the government")
}
}
class Private:School(){
fun display(){
println("They are funded by individuals")
}
}
}
fun main(){
val obj = School.Public()
obj.display()
val obj1= School.Private()
obj1.display()
}
- شما نمی توانید یک زیر کلاس از یک کلاس مهر و موم شده را در یک زیر کلاس تعریف کنید زیرا کلاس مهر و موم شده قابل مشاهده نیست.
- کلاسهای مهر و موم شده بیشتر از کی استفاده میکنند و عبارت else را حذف میکنند.
// A sealed class with a string property
sealed class Fruit(val x : String)
{
// Two subclasses of sealed class defined within
class Apple : Fruit("Apple")
class Mango : Fruit("Mango")
}
// A subclass defined outside the sealed class
class Pomegranate: Fruit("Pomegranate")
// A function to take in an object of type Fruit
// And to display an appropriate message depending on the type of Fruit
fun display(fruit: Fruit)
{
when(fruit)
{
is Fruit.Apple -> println("${fruit.x} is good for iron")
is Fruit.Mango -> println("${fruit.x} is delicious")
is Pomegranate -> println("${fruit.x} is good for vitamin d")
}
}
fun main()
{
// Objects of different subclasses created
val obj = Fruit.Apple()
val obj1 = Fruit.Mango()
val obj2 = Pomegranate()
// Function called with different objects
display(obj)
display(obj1)
display(obj2)
}
5. کلاس های حاشیه نویسی
- Annotations به برنامه نویس اجازه می دهد تا اطلاعات تکمیلی را در فایل منبع جاسازی کند. اطلاعات اعمال برنامه را تغییر نمی دهد.
`@Positive val i : Int`
- یک پارامتر را می توان در پرانتز به حاشیه نویسی مشابه فراخوانی تابع ارسال کرد.
`@Allowedlanguage("Kotlin")`
- هنگامی که یک حاشیه به عنوان پارامتر در حاشیه نویسی دیگر ارسال می شود، باید نماد @ را حذف کنیم. در اینجا حاشیه نویسی Replacewith() را به عنوان پارامتر ارسال کرده ایم.
` @Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))`
هنگامی که یک پارامتر annotation یک شی کلاس است، باید ::class را به نام کلاس اضافه کنیم:
@Throws(IOException::class)
- برای اعلام حاشیه نویسی، پیشوند کلیدواژه کلاس با کلمه کلیدی حاشیه نویسی قرار می گیرد.
- طبق ماهیت خود، اعلامیه های حاشیه نویسی نمی توانند حاوی هیچ کدی باشند.
-
هنگام اعلام حاشیه نویسی های سفارشی خود، باید مشخص کنیم که کدام عناصر کد ممکن است اعمال شوند و کجا ذخیره شوند.
ساده ترین حاشیه نویسی هیچ پارامتری نداردannotation class MyClass
-
حاشیه نویسی که به پارامتر نیاز دارد بسیار شبیه به یک کلاس با سازنده اولیه است
annotation class Suffix(val s: String)
-
همچنین می توانیم سازنده یک کلاس را حاشیه نویسی کنیم. این کار را می توان با استفاده از کلمه کلیدی سازنده برای اعلان سازنده و قرار دادن حاشیه نویسی قبل از آن انجام داد.
class MyClass@Inject constructor(dependency: MyDependency) {
//. . .
}
- ما می توانیم با افزودن یک حاشیه نویسی به ویژگی ها، ویژگی های کلاس را حاشیه نویسی کنیم.
class Lang (
@Allowedlanguages(["Java","Kotlin"]) val name: String)
}
- Kotlin همچنین حاشیه نویسی های داخلی خاصی را ارائه می دهد که برای ارائه ویژگی های بیشتر به حاشیه نویسی های تعریف شده توسط کاربر استفاده می شود.
@هدف
- این حاشیه نویسی مکان هایی را که می توان حاشیه نویسی را اعمال کرد مانند کلاس ها، توابع، سازنده ها، پارامترهای نوع و غیره مشخص می کند.
- هنگامی که یک حاشیه نویسی برای سازنده اصلی یک کلاس اعمال می شود، کلمه کلیدی سازنده قبل از سازنده مشخص می شود.
@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.LOCAL_VARIABLE)
annotation class AnnotationDemo2
class ABC @AnnotationDemo2 constructor(val count:Int){
fun display(){
println("Constructor annotated")
println("Count is $count")
}
}
fun main(){
val obj = ABC(5)
obj.display()
@AnnotationDemo2 val message: String
message = "Hello"
println("Local parameter annotated")
println(message)
}
@نگهداری
- این حاشیه نویسی در دسترس بودن حاشیه نویسی را مشخص می کند، یعنی اینکه آیا حاشیه نویسی در فایل منبع باقی می ماند یا در زمان اجرا در دسترس است و غیره.
- پارامتر مورد نیاز آن باید نمونه ای از AnnotationRetention enumeration باشد که دارای عناصر زیر باشد:
- منبع
- دودویی
- مثال RUNTIME برای نشان دادن حاشیه نویسی @Retention:
//Specifying an annotation with runtime policy
@Retention(AnnotationRetention.RUNTIME)
annotation class AnnotationDemo3
@AnnotationDemo3 fun main(){
println("Main function annotated")
}
@قابل تکرار
- این حاشیه نویسی اجازه می دهد تا یک عنصر با یک حاشیه نویسی چندین بار حاشیه نویسی شود.
- مطابق با نسخه فعلی Kotlin 1.3، این حاشیه نویسی تنها با تنظیم سیاست حفظ روی SOURCE قابل استفاده است.
@Repeatable
@Retention(AnnotationRetention.SOURCE)
annotation class AnnotationDemo4 (val value: Int)
@AnnotationDemo4(4)
@AnnotationDemo4(5)
fun main(){
println("Repeatable Annotation applied on main")
}
💫💫از اینکه برای خواندن مقاله من وقت گذاشتید متشکرم، از علاقه و حمایت شما سپاسگزارم. امیدوارم لذت برده باشید😇😇🥳🥳