Kelas Abstrak

Kelas abstrak adalah kelas yang membuat beberapa atau semua anggota tidak diimplementasikan, sehingga implementasi dapat disediakan oleh kelas turunan.

Sintaks

// Abstract class syntax.
[<AbstractClass>]
type [ accessibility-modifier ] abstract-class-name =
[ inherit base-class-or-interface-name ]
[ abstract-member-declarations-and-member-definitions ]

// Abstract member syntax.
abstract member member-name : type-signature

Keterangan

Dalam pemrograman berorientasi pada objek, kelas abstrak digunakan sebagai kelas dasar hierarki, dan mewakili fungsionalitas umum dari beragam jenis objek. Seperti namanya, "abstrak" menyiratkan kelas abstrak yang sering kali tidak sesuai langsung ke entitas konkret di domain masalah. Namun, mereka mewakili kesamaan yang dimiliki banyak entitas konkret yang berbeda.

Kelas abstrak harus memiliki atribut AbstractClass. Mereka dapat memiliki anggota yang diimplementasikan dan tidak diimplementasikan. Penggunaan istilah abstrak ketika diterapkan ke kelas sama seperti dalam bahasa .NET lainnya; namun, penggunaan istilah abstrak ketika diterapkan ke metode (dan properti) sedikit berbeda dalam F# dari penggunaannya dalam bahasa .NET lainnya. Di F#, ketika metode ditandai dengan kata kunci abstract, ini menunjukkan bahwa anggota memiliki entri, yang dikenal sebagai slot pengiriman virtual, dalam tabel internal fungsi virtual untuk jenis tersebut. Dengan kata lain, metode ini virtual, meskipun kata kunci virtual tidak digunakan dalam F#. Kata kunci abstract digunakan pada metode virtual terlepas dari apakah metode tersebut diimplementasikan. Deklarasi slot pengiriman virtual terpisah dari definisi metode untuk slot pengiriman tersebut. Oleh karena itu, F# yang setara dengan deklarasi metode virtual dan definisi dalam bahasa .NET lain adalah kombinasi dari deklarasi metode abstrak dan definisi terpisah, dengan kata kunci default atau kata kunci override. Untuk informasi dan contoh selengkapnya, lihat Metode.

Kelas dianggap abstrak hanya jika ada metode abstrak yang dinyatakan tetapi tidak didefinisikan. Oleh karena itu, kelas yang memiliki metode abstrak belum tentu kelas abstrak. Jangan gunakan atribut AbstractClass kecuali kelas memiliki metode abstrak yang tidak terdefinisi.

Dalam sintaks sebelumnya, pengubah aksesibilitas dapat berupa public, private, atau internal. Untuk informasi selengkapnya, lihat Kontrol Akses.

Seperti jenis lainnya, kelas abstrak dapat memiliki kelas dasar dan satu atau beberapa antarmuka dasar. Setiap kelas dasar atau antarmuka muncul pada baris terpisah bersama dengan kata kunci inherit.

Definisi jenis kelas abstrak dapat berisi anggota yang sepenuhnya ditentukan, tetapi juga dapat berisi anggota abstrak. Sintaks untuk anggota abstrak ditampilkan secara terpisah dalam sintaks sebelumnya. Dalam sintaks ini, tanda tangan jenis anggota adalah daftar yang berisi jenis parameter secara berurutan dan jenis pengembalian, dipisahkan oleh token -> dan/atau token * yang sesuai untuk parameter kurir dan tupled. Sintaks untuk tanda tangan jenis anggota abstrak sama dengan yang digunakan dalam file tanda tangan dan yang ditampilkan oleh IntelliSense di editor Visual Studio Code.

Kode berikut menggambarkan Bentuk kelas abstrak, yang memiliki dua kelas turunan non-abstrak, Persegi, dan Lingkaran. Contoh ini menunjukkan cara menggunakan kelas, metode, dan properti abstrak. Dalam contoh, Bentuk kelas abstrak mewakili elemen umum dari entitas konkret lingkaran dan persegi. Fitur umum dari semua bentuk (dalam sistem koordinat dua dimensi) diabstraksikan ke dalam kelas Bentuk: posisi pada grid, sudut rotasi, dan properti area dan perimeter. Ini dapat ditimpa, kecuali untuk posisi, perilaku yang bentuk individunya tidak dapat berubah.

Metode rotasi dapat diganti, seperti pada kelas Lingkaran, yang rotasinya tidak berubah karena bentuknya simetris. Jadi di kelas Lingkaran, metode rotasi diganti dengan metode yang tidak melakukan apa-apa.

// An abstract class that has some methods and properties defined
// and some left abstract.
[<AbstractClass>]
type Shape2D(x0: float, y0: float) =
    let mutable x, y = x0, y0
    let mutable rotAngle = 0.0

    // These properties are not declared abstract. They
    // cannot be overriden.
    member this.CenterX
        with get () = x
        and set xval = x <- xval

    member this.CenterY
        with get () = y
        and set yval = y <- yval

    // These properties are abstract, and no default implementation
    // is provided. Non-abstract derived classes must implement these.
    abstract Area: float with get
    abstract Perimeter: float with get
    abstract Name: string with get

    // This method is not declared abstract. It cannot be
    // overridden.
    member this.Move dx dy =
        x <- x + dx
        y <- y + dy

    // An abstract method that is given a default implementation
    // is equivalent to a virtual method in other .NET languages.
    // Rotate changes the internal angle of rotation of the square.
    // Angle is assumed to be in degrees.
    abstract member Rotate: float -> unit
    default this.Rotate(angle) = rotAngle <- rotAngle + angle

type Square(x, y, sideLengthIn) =
    inherit Shape2D(x, y)
    member this.SideLength = sideLengthIn
    override this.Area = this.SideLength * this.SideLength
    override this.Perimeter = this.SideLength * 4.
    override this.Name = "Square"

type Circle(x, y, radius) =
    inherit Shape2D(x, y)
    let PI = 3.141592654
    member this.Radius = radius
    override this.Area = PI * this.Radius * this.Radius
    override this.Perimeter = 2. * PI * this.Radius
    // Rotating a circle does nothing, so use the wildcard
    // character to discard the unused argument and
    // evaluate to unit.
    override this.Rotate(_) = ()
    override this.Name = "Circle"

let square1 = new Square(0.0, 0.0, 10.0)
let circle1 = new Circle(0.0, 0.0, 5.0)
circle1.CenterX <- 1.0
circle1.CenterY <- -2.0
square1.Move -1.0 2.0
square1.Rotate 45.0
circle1.Rotate 45.0
printfn "Perimeter of square with side length %f is %f, %f" (square1.SideLength) (square1.Area) (square1.Perimeter)
printfn "Circumference of circle with radius %f is %f, %f" (circle1.Radius) (circle1.Area) (circle1.Perimeter)

let shapeList: list<Shape2D> = [ (square1 :> Shape2D); (circle1 :> Shape2D) ]
List.iter (fun (elem: Shape2D) -> printfn "Area of %s: %f" (elem.Name) (elem.Area)) shapeList

Output:

Perimeter of square with side length 10.000000 is 40.000000
Circumference of circle with radius 5.000000 is 31.415927
Area of Square: 100.000000
Area of Circle: 78.539816

Lihat juga