F # - Наследование

Одна из наиболее важных концепций объектно-ориентированного программирования - это наследование. Наследование позволяет нам определять класс в терминах другого класса, что упрощает создание и поддержку приложения. Это также дает возможность повторно использовать функциональность кода и быстрое время реализации.

При создании класса вместо написания полностью новых элементов данных и функций-членов программист может указать, что новый класс должен наследовать члены существующего класса. Этот существующий класс называется базовым классом, а новый класс - производным классом.

Идея наследования реализует отношения IS-A. Например, млекопитающее - это животное, собака - это млекопитающее, следовательно, собака - это тоже животное, и так далее.

Базовый класс и подкласс

Подкласс является производным от базового класса, который уже определен. Подкласс наследует члены базового класса, а также имеет свои собственные члены.

Подкласс определяется с помощью inherit ключевое слово, как показано ниже -

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

В F # класс может иметь не более одного прямого базового класса. Если вы не укажете базовый класс с помощьюinherit ключевое слово, класс неявно наследуется от Object.

Обратите внимание -

  • Методы и члены базового класса доступны пользователям производного класса, как прямые члены производного класса.

  • Пусть привязки и параметры конструктора являются частными для класса и, следовательно, не могут быть доступны из производных классов.

  • Ключевое слово baseотносится к экземпляру базового класса. Он используется как самоидентификатор.

пример

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Переопределение методов

Вы можете переопределить поведение метода базового класса по умолчанию и по-другому реализовать его в подклассе или производном классе.

По умолчанию методы в F # не подлежат переопределению.

Чтобы переопределить методы в производном классе, вы должны объявить свой метод как переопределяемый с помощью abstract и default ключевые слова следующим образом -

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

Теперь метод Greet класса Person можно переопределить в производных классах. Следующий пример демонстрирует это -

пример

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Абстрактный класс

Иногда вам необходимо предоставить неполную реализацию объекта, что не должно быть реализовано в реальности. Позже другой программист должен создать подклассы абстрактного класса для полной реализации.

Например, класс Person не понадобится в системе управления школой. Тем не менее, понадобится класс ученика или учителя. В таких случаях вы можете объявить класс Person как абстрактный класс.

В AbstractClass Атрибут сообщает компилятору, что у класса есть некоторые абстрактные члены.

Вы не можете создать экземпляр абстрактного класса, потому что класс реализован не полностью.

Следующий пример демонстрирует это -

пример

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Student Zara
Teacher Mariam.