Bagikan melalui


Kelas Abstrak

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

Sintaksis

// 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

Komentar

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

Kelas abstrak harus memiliki AbstractClass atribut . Mereka dapat mengimplementasikan dan anggota yang tidak terimplementasi. Penggunaan istilah abstrak saat 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 abstract kata kunci, 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 virtual kata kunci tidak digunakan dalam F#. Kata kunci abstract digunakan pada metode virtual terlepas dari apakah metode diimplementasikan. Deklarasi slot pengiriman virtual terpisah dari definisi metode untuk slot pengiriman tersebut. Oleh karena itu, F# yang setara dengan deklarasi dan definisi metode virtual dalam bahasa .NET lain adalah kombinasi dari deklarasi metode abstrak dan definisi terpisah, dengan default kata kunci atau override kata kunci. Untuk informasi dan contoh selengkapnya, lihat Metode.

Kelas dianggap abstrak hanya jika ada metode abstrak yang dideklarasikan tetapi tidak ditentukan. Oleh karena itu, kelas yang memiliki metode abstrak belum tentu merupakan kelas abstrak. Kecuali kelas memiliki metode abstrak yang tidak terdefinisi, jangan gunakan atribut AbstractClass .

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

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

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 ditunjukkan oleh IntelliSense di Editor Visual Studio Code.

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

Metode rotasi dapat ditimpa, seperti di kelas Lingkaran, yang invarian rotasi karena simetrinya. Jadi di kelas Lingkaran, metode rotasi digantikan oleh metode yang tidak melakukan apa pun.

// 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

Hasil:

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