F # - การถ่ายทอดทางพันธุกรรม

แนวคิดที่สำคัญที่สุดอย่างหนึ่งในการเขียนโปรแกรมเชิงวัตถุคือการสืบทอด การสืบทอดช่วยให้เรากำหนดคลาสในรูปแบบของคลาสอื่นซึ่งทำให้ง่ายต่อการสร้างและดูแลแอปพลิเคชัน นอกจากนี้ยังให้โอกาสในการนำฟังก์ชันโค้ดกลับมาใช้ซ้ำและใช้งานได้รวดเร็ว

เมื่อสร้างคลาสแทนที่จะเขียนสมาชิกข้อมูลและฟังก์ชันสมาชิกใหม่ทั้งหมดโปรแกรมเมอร์สามารถกำหนดได้ว่าคลาสใหม่ควรสืบทอดสมาชิกของคลาสที่มีอยู่ คลาสที่มีอยู่นี้เรียกว่าคลาสพื้นฐานและคลาสใหม่เรียกว่าคลาสที่ได้รับ

แนวคิดเรื่องการถ่ายทอดทางพันธุกรรมดำเนินความสัมพันธ์ IS-A ตัวอย่างเช่นสัตว์เลี้ยงลูกด้วยนมเป็นสัตว์สุนัข IS-A สัตว์เลี้ยงลูกด้วยนมดังนั้นสุนัข 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

ตอนนี้วิธีการทักทายของคลาส 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 เป็นคลาสนามธรรมได้

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.