F # - Kế thừa

Một trong những khái niệm quan trọng nhất trong lập trình hướng đối tượng là tính kế thừa. Tính kế thừa cho phép chúng ta xác định một lớp theo nghĩa của một lớp khác, giúp tạo và duy trì một ứng dụng dễ dàng hơn. Điều này cũng tạo cơ hội để sử dụng lại chức năng mã và thời gian thực hiện nhanh chóng.

Khi tạo một lớp, thay vì viết các thành viên dữ liệu hoàn toàn mới và các hàm thành viên, lập trình viên có thể chỉ định rằng lớp mới sẽ kế thừa các thành viên của một lớp hiện có. Lớp hiện có này được gọi là lớp cơ sở và lớp mới được gọi là lớp dẫn xuất.

Ý tưởng kế thừa thực hiện mối quan hệ IS-A. Ví dụ, động vật có vú LÀ Động vật, chó IS-Động vật có vú, do đó chó IS-A động vật cũng như vậy.

Lớp cơ sở và Lớp phụ

Một lớp con có nguồn gốc từ một lớp cơ sở, lớp này đã được định nghĩa. Một lớp con kế thừa các thành viên của lớp cơ sở, cũng như có các thành viên riêng của nó.

Một lớp con được xác định bằng cách sử dụng inherit từ khóa như hình bên dưới -

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

Trong F #, một lớp có thể có nhiều nhất một lớp cơ sở trực tiếp. Nếu bạn không chỉ định một lớp cơ sở bằng cách sử dụnginherit từ khóa, lớp kế thừa ngầm định từ Object.

Xin lưu ý -

  • Các phương thức và thành viên của lớp cơ sở có sẵn cho người dùng của lớp dẫn xuất giống như các thành viên trực tiếp của lớp dẫn xuất.

  • Hãy để các ràng buộc và tham số hàm tạo là riêng tư đối với một lớp và do đó, không thể được truy cập từ các lớp dẫn xuất.

  • Từ khóa baseđề cập đến cá thể lớp cơ sở. Nó được sử dụng giống như mã định danh tự.

Thí dụ

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

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

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

Phương pháp ghi đè

Bạn có thể ghi đè một hành vi mặc định của một phương thức lớp cơ sở và triển khai nó theo cách khác trong lớp con hoặc lớp dẫn xuất.

Các phương thức trong F # không được ghi đè theo mặc định.

Để ghi đè các phương thức trong một lớp dẫn xuất, bạn phải khai báo phương thức của mình là có thể ghi đè bằng cách sử dụng abstractdefault từ khóa như sau -

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

Bây giờ, phương thức Greet của lớp Person có thể được ghi đè trong các lớp dẫn xuất. Ví dụ sau đây chứng minh điều này -

Thí dụ

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

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Lớp trừu tượng

Đôi khi bạn cần cung cấp một bản triển khai không đầy đủ của một đối tượng, điều này không nên được triển khai trong thực tế. Sau đó, một số lập trình viên khác nên tạo các lớp con của lớp trừu tượng để thực hiện hoàn chỉnh.

Ví dụ, lớp Person sẽ không cần thiết trong Hệ thống quản lý trường học. Tuy nhiên, học viên hoặc giáo viên sẽ là cần thiết. Trong những trường hợp như vậy, bạn có thể khai báo lớp Person là một lớp trừu tượng.

Các AbstractClass thuộc tính cho trình biên dịch biết rằng lớp có một số thành viên trừu tượng.

Bạn không thể tạo một thể hiện của một lớp trừu tượng vì lớp đó không được triển khai đầy đủ.

Ví dụ sau đây chứng minh điều này -

Thí dụ

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

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

Student Zara
Teacher Mariam.