F # - dziedziczenie

Jedną z najważniejszych koncepcji programowania obiektowego jest dziedziczenie. Dziedziczenie pozwala nam zdefiniować klasę pod względem innej klasy, co ułatwia tworzenie i utrzymywanie aplikacji. Daje to również możliwość ponownego wykorzystania funkcjonalności kodu i szybkiego czasu implementacji.

Tworząc klasę, zamiast pisać zupełnie nowe składowe danych i funkcje składowe, programista może wyznaczyć, że nowa klasa powinna dziedziczyć składowe istniejącej klasy. Ta istniejąca klasa jest nazywana klasą bazową, a nowa klasa jest nazywana klasą pochodną.

Idea dziedziczenia implementuje relację IS-A. Na przykład, ssak JEST zwierzęciem, pies IS-A ssak, stąd pies również jest zwierzęciem IS-A i tak dalej.

Klasa podstawowa i podklasa

Podklasa pochodzi z klasy bazowej, która jest już zdefiniowana. Podklasa dziedziczy członków klasy bazowej, a także ma swoich własnych członków.

Podklasa jest definiowana za pomocą inherit słowo kluczowe, jak pokazano poniżej -

type MyDerived(...) =
   inherit MyBase(...)

W języku F # klasa może mieć co najwyżej jedną bezpośrednią klasę bazową. Jeśli nie określisz klasy bazowej przy użyciuinherit słowo kluczowe, klasa dziedziczy niejawnie po Object.

Uwaga -

  • Metody i elementy członkowskie klasy bazowej są dostępne dla użytkowników klasy pochodnej, podobnie jak bezpośredni członkowie klasy pochodnej.

  • Niech powiązania i parametry konstruktora są prywatne dla klasy i dlatego nie można uzyskać do nich dostępu z klas pochodnych.

  • Słowo kluczowe baseodwołuje się do instancji klasy bazowej. Jest używany jako własny identyfikator.

Przykład

type Person(name) =
   member x.Name = name
   member x.Greet() = printfn "Hi, I'm %s" x.Name

type Student(name, studentID : int) =
   inherit Person(name)
   let mutable _GPA = 0.0
   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value

type Teacher(name, expertise : string) =
   inherit Person(name)

   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value
   member x.Expertise = expertise

//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

p.Greet()
st.Greet()
tr.Greet()

Kiedy kompilujesz i wykonujesz program, daje to następujące dane wyjściowe -

Hi, I'm Mohan
Hi, I'm Zara
Hi, I'm Mariam

Metody zastępujące

Można przesłonić domyślne zachowanie metody klasy bazowej i zaimplementować je inaczej w podklasie lub klasie pochodnej.

Metody w języku F # nie są domyślnie zastępowalne.

Aby przesłonić metody w klasie pochodnej, musisz zadeklarować swoją metodę jako możliwą do zastąpienia przy użyciu abstract i default słowa kluczowe w następujący sposób -

type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit
   default x.Greet() = printfn "Hi, I'm %s" x.Name

Teraz metodę Greet klasy Person można zastąpić w klasach pochodnych. Poniższy przykład demonstruje to -

Przykład

type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit
   default x.Greet() = printfn "Hi, I'm %s" x.Name

type Student(name, studentID : int) =
   inherit Person(name)

   let mutable _GPA = 0.0

   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value
   override x.Greet() = printfn "Student %s" x.Name

type Teacher(name, expertise : string) =
   inherit Person(name)
   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value

   member x.Expertise = expertise
   override x.Greet() = printfn "Teacher %s." x.Name

//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

//default Greet
p.Greet()

//Overriden Greet
st.Greet()
tr.Greet()

Kiedy kompilujesz i wykonujesz program, daje to następujące dane wyjściowe -

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Klasa abstrakcyjna

Czasami trzeba zapewnić niepełną implementację obiektu, który w rzeczywistości nie powinien być implementowany. Później jakiś inny programista powinien utworzyć podklasy klasy abstrakcyjnej do pełnej implementacji.

Na przykład klasa Person nie będzie potrzebna w systemie zarządzania szkołą. Jednak klasa ucznia lub nauczyciela będzie potrzebna. W takich przypadkach można zadeklarować klasę Person jako klasę abstrakcyjną.

Plik AbstractClass atrybut mówi kompilatorowi, że klasa ma kilka abstrakcyjnych elementów członkowskich.

Nie można utworzyć wystąpienia klasy abstrakcyjnej, ponieważ klasa ta nie jest w pełni zaimplementowana.

Poniższy przykład demonstruje to -

Przykład

[<AbstractClass>]
type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit

type Student(name, studentID : int) =
   inherit Person(name)
   let mutable _GPA = 0.0
   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value
   override x.Greet() = printfn "Student %s" x.Name

type Teacher(name, expertise : string) =
   inherit Person(name)
   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value
   member x.Expertise = expertise
   override x.Greet() = printfn "Teacher %s." x.Name

let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

//Overriden Greet
st.Greet()
tr.Greet()

Kiedy kompilujesz i wykonujesz program, daje to następujące dane wyjściowe -

Student Zara
Teacher Mariam.