Megosztás a következőn keresztül:


Absztrakt osztályok

Az absztrakt osztályok olyan osztályok, amelyek bizonyos vagy az összes tagot akadálytalanul hagynak, hogy a megvalósításokat származtatott osztályok biztosíthassák.

Syntax

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

Megjegyzések

Az objektumorientált programozásban az absztrakt osztályt egy hierarchia alaposztályaként használják, és különböző objektumtípusok közös funkcióit képviselik. Ahogy az "absztrakt" név is mutatja, az absztrakt osztályok gyakran nem felelnek meg közvetlenül a problémás tartomány konkrét entitásainak. Ezek azonban azt képviselik, ami sok különböző konkrét entitásban közös.

Az absztrakt osztályoknak rendelkezniük kell az AbstractClass attribútummal. Lehetnek implementált és nem tagolt tagjaik. Az absztrakt kifejezés használata az osztályra alkalmazva ugyanaz, mint a többi .NET-nyelv esetében, azonban az absztrakt kifejezés használata metódusokra (és tulajdonságokra) alkalmazva kissé eltér az F#-ban a más .NET-nyelvekben való használattól. Az F#-ban, ha egy metódus a kulcsszóval abstract van megjelölve, az azt jelzi, hogy egy tagnak van egy bejegyzése, más néven virtuális feladóhely a virtuális függvények belső táblázatában az adott típushoz. Más szóval a metódus virtuális, bár a virtual kulcsszó nem használatos az F#-ban. A kulcsszót abstract a rendszer a virtuális metódusokon használja, függetlenül attól, hogy a metódus implementálva van-e. A virtuális feladási pont deklarációja eltér az adott feladási ponthoz tartozó metódus definíciójától. Ezért egy virtuális metódus deklarációjának és definíciójának F# megfelelője egy másik .NET-nyelven egy absztrakt metódusdefiníció és egy külön definíció kombinációja, akár a default kulcsszó, akár a override kulcsszó. További információkért és példákért lásd a Metódusok című témakört.

Az osztály csak akkor tekinthető absztraktnak, ha vannak deklarált, de nem definiált absztrakt metódusok. Ezért az absztrakt metódusokkal rendelkező osztályok nem feltétlenül absztrakt osztályok. Ha egy osztály nem definiált absztrakt metódusokat használ, ne használja az AbstractClass attribútumot.

Az előző szintaxisban az akadálymentesség-módosító lehet public, private vagy internal. Ezzel kapcsolatos további információt a Hozzáférés-vezérléscímű témakörben talál.

Más típusokhoz hasonlóan az absztrakt osztályok is rendelkezhetnek alaposztályokkal és egy vagy több alapillesztővel. Minden alaposztály vagy felület külön sorban jelenik meg a inherit kulcsszóval együtt.

Az absztrakt osztály típusdefiníciója teljes mértékben definiált tagokat tartalmazhat, de absztrakt tagokat is tartalmazhat. Az absztrakt tagok szintaxisa külön jelenik meg az előző szintaxisban. Ebben a szintaxisban a tag típusaadéka egy lista, amely sorrendben tartalmazza a paramétertípusokat és a visszatérési típusokat, jogkivonatokkal és/vagy * jogkivonatokkal elválasztva->, a curried és a tupled paramétereknek megfelelően. Az absztrakt tag típusú aláírások szintaxisa megegyezik az aláírásfájlokban használt és a Visual Studio Code Editor IntelliSense által megjelenített szintaxisával.

Az alábbi kód egy absztrakt alakzatosztályt mutat be, amely két nem absztrakt származtatott osztályt, a Négyzetet és a Kört tartalmazza. A példa az absztrakt osztályok, metódusok és tulajdonságok használatát mutatja be. A példában az absztrakt Alakzat osztály a konkrét entitások kör és négyzet közös elemeit jelöli. Az alakzatok (kétdimenziós koordinátarendszerben) közös jellemzői az Alakzat osztályba kerülnek: a rács elhelyezkedése, a forgatási szög, valamint a terület- és szegélytulajdonságok. Ezek felülbírálódhatnak, kivéve a pozíciót, amelynek viselkedését az egyes alakzatok nem módosíthatják.

A rotációs módszer felül lehet bírálni, mint a Circle osztályban, amely a szimmetria miatt invariáns. A Circle osztályban tehát a rotációs metódust egy olyan metódus váltja fel, amely nem tesz semmit.

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

Kimeneti:

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

Lásd még