کلاس های ابسترکت (abstract) در کاتلین

کلاس های ابسترکت (abstract) در کاتلین

توضیحات و ویژگی ها

به کلاس، تابع و پراپرتی های معمولی concrete میگیم اما نوعی از کلاس در کاتلین وجود داره که بهش abstract میگیم و میتونیم داخلش علاوه بر توابع و پراپرتی های concrete، توابع و پراپرتی های abstract نیز تعریف کنیم.

میتونیم یک تابع (متد) رو abstract تعریف کنیم و هنگام ارث بری و بازنویسی تابعو کامل پیاده‌سازی کنیم برای این کار تابع باید در کلاس abstract یا در interface تعریف بشه و هنگام ارث بری بازنویسی بشه، در این مطلب کلاس های ابسترکت رو بررسی میکنیم و در مطلب بعدی به اینترفیس ها می پردازیم.

برای تعریف کلاس ابسترکت از کلیدواژه ی abstract قبل از کلیدواژه ی class استفاده میکنیم و برای تعریف پراپرتی و توابع ابسترکت هم مثل کلاس ابسترکت ابتدا کلیدواژه ی abstract رو مینویسیم.

با اینکه میتونیم در کلاس ابسترکت، کانستراکتور تعریف کنیم اما نمیتونیم مستقیم از این کلاس ها نمونه (شی) سازی کنیم و باید از ساب کلاسی که concrete است نمونه سازی کنیم.

فرم کلی کلاس های ابسترکت:

abstract class MyAbstractClass{
  //abstract property
  abstract val t0: T

  //concrete property
  val t1: T = ...

  ...

  //abstract function
  abstract fun myAbstractFunction(t: T)

  //concrete function
  fun myFunction(t: T){

    //Do Something Here...

  }
  ...
}
                  

همینطور که در بالا مشخصه در کلاس های ابسترکت، علاوه بر توابع و متغیر های concrete توابع و متغیر های abstract نیز میتونیم تعریف کنیم.

اگه ساب کلاس concrete بود توابع و پراپرتی های abstract تعریف شده در سوپر کلاس باید به صورت concrete (کامل) در subclass بازنویسی بشن

مثال

فرض کنید کلاس Foo سوپر کلاس و Bar ساب کلاس Foo است.

abstract class Foo{
  abstract val prop0: String

  abstract fun abstractSayHello()

  fun concreteSayHello(){
    println("Hello from concrete function!")
  }
}

class Bar: Foo{

  override val prop0 = "Hello from abstract property!"

  override fun abstractSayHello(){
    println("Hello from Abstract function!")
  }

}

fun main(){

  val bar = Bar()

  println(bar.prop0)

  bar.abstractSayHello()
  bar.concreteSayHello()

}
                  

هنگامی که در یک کلاس abstract متغیر یا تابع abstract تعریف نکنیم معمولا به عنوان کلاس Base در نظرش میگیریم. کلاس Base پایه و سوپر کلاس تمام subclass های یک بخشی از پروژه است.

abstract class MyBase{
  //without abstract properties and (or) functions
  ...

}
                  

مورد مطالعه (مثال ها)

در مطلب وراثت کلاس Circle و Rectangle از کلاس GeometricShape ارث بری کردن و کلاس GeometricShape از کلاس Shape.

نمودار رابطه ی بین این چهار کلاس نیز در زیر ترسیم شده:

رابطه ی ارث بری بین چهار کلاس
ارث بری از Shape و GeometricShape

حالا میخوایم دو کلاس Shape و GeometricShape رو به صورت abstract تعربف کنیم:

abstract class Shape(var color: String, var isFilled: Boolean = false){
  
  val dateCreated = java.util.Date()

  override fun toString(): String{
    return "Shape created at $dateCreated \ncolor is $color, \nisFilled? $isFilled"
  }

}

abstract class GeometricShape(color: String, isFilled: Boolean): Shape(color, isFilled){

  abstract val area: Int
  abstract val perimeter: Int

  constructor(): this("White", false)

  override fun toString(): String{
    return super.toString() + "\nArea is $area \nperimeter is $perimeter \nX is $x and Y is $y"
  }

  override fun equals(other: Any?): Boolean{
    if(other !is GeometricShape) 
      throw IllegalArgumentException("GeometricShape argument required")

      return other.area == this.area
  }
}

// تعریف کلاس دایره
class Circle: GeometricShape{

  var radius = 1

  override val area get() = (radius * radius * PI).toInt()

  override val perimeter get() = (2 * radius * PI).toInt()

  constructor(radius: Int, color: String, isFilled: Boolean): super(color, isFilled){
   this.radius = radius
}

  constructor(): super()

  constructor(radius: Int): super(){
    this.radius = radius
  }
 
  override fun toString(): String{
    val fromGeometricShape = super.toString()

    return fromGeometricShape + "\nThe shape is Circle!"
  }  
}

// تعریف کلاس مستطیل
class Rectangle: GeometricShape{

  var width = 1
  var height = 1

  override val area get() = width * height

  override val perimeter get() = (width + height) * 2

  constructor(width: Int, height: Int, color: String, isFilled: Boolean): super(color, isFilled){
   this.width = width
   this.height = height
}

  constructor(): super()

  constructor(width: Int, height: Int): super(){
    this.width = width
    this.height = height
  }

  fun isSquare(): Boolean = (width == height)
 
  override fun toString(): String{
    val fromGeometricShape = super.toString()

    return fromGeometricShape + "\nThe shape is Rectangle!"
  }
  
}

fun main(){

    val c = Circle(2)
    c.stroke = "Blue"

    val c1 = Circle(radius = 5, x = 1, y =  1, "Yellow", true)

    val rect = Rectangle(3 , 4)

    val rect1 = Rectangle(7, 7)

    println("$c")

    println("\n$c1")

    println("\n$rect")

    println("\n$rect1")

    println()

    println("Are c and rect equal? ${c.equals(rect)}")

    println("Are c1 and c equal? ${c1.equals(c)}" )

    println()

    println("Is rect square? ${rect.isSquare()}")

    println("Is rect1 square? ${rect1.isSquare()}")

}
                  

خلاصه

  • به توابع و متغیر های کامل concrete میگیم.
  • - متغیر و پراپرتی های ابسترکت رو‌فقط داخل کلاس ابسترکت یا داهل اینترفیس مبتونیم تعریف کنیم.
  • در کلاس ابسترکت علاوه بر پراپرتی و توابع ابسترکت میتونیم پراپرتی و توابع کامل (concrete) نیز تعریف کنیم.
  • با اینکه میتونیم برای کلاس ابسترکت، کانستراکتور تعریف کنیم اما نمیتونیم از اون کلاس نمونه ایجاد کنیم.
  • معمولا کلاس ابسترکتی که پراپرتی و تابع ابسترکت نداشته باشه رو به عنوان کلاس Base تعریف میکنن.

برای اطلاع از جدیدترین مطالب یا پرسش و پاسخ عضو کانال و گروه تلگرامی ما شوید.

arrow_drop_up
کپی شد!