F # - Eredità

Uno dei concetti più importanti nella programmazione orientata agli oggetti è quello dell'ereditarietà. L'ereditarietà ci consente di definire una classe in termini di un'altra classe, il che semplifica la creazione e la manutenzione di un'applicazione. Ciò offre anche l'opportunità di riutilizzare la funzionalità del codice e tempi di implementazione rapidi.

Quando si crea una classe, invece di scrivere membri dati e funzioni membro completamente nuovi, il programmatore può designare che la nuova classe erediti i membri di una classe esistente. Questa classe esistente viene chiamata classe base e la nuova classe viene definita classe derivata.

L'idea di eredità implementa la relazione IS-A. Ad esempio, il mammifero è un animale, il cane è un mammifero quindi anche il cane è un animale e così via.

Classe di base e sottoclasse

Una sottoclasse è derivata da una classe base, che è già definita. Una sottoclasse eredita i membri della classe di base e dispone dei propri membri.

Una sottoclasse viene definita utilizzando il inherit parola chiave come mostrato di seguito -

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

In F # una classe può avere al massimo una classe base diretta. Se non si specifica una classe di base utilizzando ilinherit parola chiave, la classe eredita implicitamente da Object.

Nota:

  • I metodi ei membri della classe base sono disponibili per gli utenti della classe derivata come i membri diretti della classe derivata.

  • Lascia che i collegamenti ei parametri del costruttore siano privati ​​di una classe e, pertanto, non è possibile accedervi dalle classi derivate.

  • La parola chiave basesi riferisce all'istanza della classe base. È usato come l'identificatore di sé.

Esempio

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()

Quando compili ed esegui il programma, restituisce il seguente output:

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

Metodi di sostituzione

È possibile sovrascrivere un comportamento predefinito di un metodo della classe base e implementarlo in modo diverso nella sottoclasse o nella classe derivata.

I metodi in F # non possono essere sovrascritti per impostazione predefinita.

Per sovrascrivere i metodi in una classe derivata, devi dichiarare il tuo metodo come sovrascrivibile usando il abstract e default parole chiave come segue:

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

Ora, il metodo Greet della classe Person può essere sovrascritto nelle classi derivate. Il seguente esempio lo dimostra:

Esempio

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()

Quando compili ed esegui il programma, restituisce il seguente output:

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Classe astratta

A volte è necessario fornire un'implementazione incompleta di un oggetto, che non dovrebbe essere implementata nella realtà. Successivamente, qualche altro programmatore dovrebbe creare sottoclassi della classe astratta per un'implementazione completa.

Ad esempio, la classe Persona non sarà necessaria in un sistema di gestione scolastica. Tuttavia, sarà necessaria la classe Studente o Insegnante. In questi casi, puoi dichiarare la classe Person come classe astratta.

Il AbstractClass attributo dice al compilatore che la classe ha alcuni membri astratti.

Non è possibile creare un'istanza di una classe astratta perché la classe non è completamente implementata.

Il seguente esempio lo dimostra:

Esempio

[<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()

Quando compili ed esegui il programma, restituisce il seguente output:

Student Zara
Teacher Mariam.