F # - Herança

Um dos conceitos mais importantes na programação orientada a objetos é o de herança. A herança nos permite definir uma classe em termos de outra classe, o que torna mais fácil criar e manter um aplicativo. Isso também oferece uma oportunidade de reutilizar a funcionalidade do código e tempo de implementação rápido.

Ao criar uma classe, em vez de escrever membros de dados e funções de membro completamente novos, o programador pode designar que a nova classe deve herdar os membros de uma classe existente. Essa classe existente é chamada de classe base e a nova classe é chamada de classe derivada.

A ideia de herança implementa o relacionamento IS-A. Por exemplo, o mamífero é um animal, o cão é um mamífero, portanto, o cão é também um animal e assim por diante.

Classe Base e Subclasse

Uma subclasse é derivada de uma classe base, que já está definida. Uma subclasse herda os membros da classe base, bem como tem seus próprios membros.

Uma subclasse é definida usando o inherit palavra-chave conforme mostrado abaixo -

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

Em F #, uma classe pode ter no máximo uma classe base direta. Se você não especificar uma classe base usando oinherit palavra-chave, a classe herda implicitamente de Object.

Observe -

  • Os métodos e membros da classe base estão disponíveis para usuários da classe derivada, como os membros diretos da classe derivada.

  • Deixe que as ligações e os parâmetros do construtor sejam privados para uma classe e, portanto, não podem ser acessados ​​de classes derivadas.

  • A palavra-chave baserefere-se à instância da classe base. Ele é usado como o auto-identificador.

Exemplo

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 você compila e executa o programa, ele produz a seguinte saída -

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

Métodos de substituição

Você pode substituir um comportamento padrão de um método da classe base e implementá-lo de maneira diferente na subclasse ou na classe derivada.

Os métodos em F # não podem ser substituídos por padrão.

Para substituir métodos em uma classe derivada, você deve declarar seu método como substituível usando o abstract e default palavras-chave da seguinte forma -

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

Agora, o método Greet da classe Person pode ser substituído nas classes derivadas. O exemplo a seguir demonstra isso -

Exemplo

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 você compila e executa o programa, ele produz a seguinte saída -

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Classe Abstrata

Às vezes, você precisa fornecer uma implementação incompleta de um objeto, que não deveria ser implementada na realidade. Posteriormente, algum outro programador deve criar subclasses da classe abstrata para uma implementação completa.

Por exemplo, a classe Person não será necessária em um Sistema de Gestão Escolar. No entanto, a classe do aluno ou do professor será necessária. Nesses casos, você pode declarar a classe Person como uma classe abstrata.

o AbstractClass atributo informa ao compilador que a classe possui alguns membros abstratos.

Você não pode criar uma instância de uma classe abstrata porque a classe não está totalmente implementada.

O exemplo a seguir demonstra isso -

Exemplo

[<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 você compila e executa o programa, ele produz a seguinte saída -

Student Zara
Teacher Mariam.