KẾ THỪA TRONG RUBY

1.Cấu trúc một object trong Ruby

Để có thể hiểu sâu sắc về kế thừa trong Ruby trước tiên chúng ta sẽ đi tìm hiểu cấu trúc của một Object trong Ruby. Khi được khởi tạo vùng nhớ thì một Object trong Ruby sẽ có các trường sau:

  • kclass: Một con trỏ trỏ đến class của object này
  • iv_tbl: “instance variable table” một mảng băm chưa đựng các biến instance của đối tượng này
  • flags: một tập các cờ trạng thái Boolean của Object như cờ báo trạng thái Object bị hỏng, bị garbage collection đánh dấu, bị khóa ...

Mỗi một class hay module ngoài các trường ở trên còn có thêm 2 trường nữa:

  • m_tbl: “Method Table”, một bảng băm chứa đựng địa chỉ các instance method của class hay module
  • super: con trỏ trỏ đến lớp cha của nó

Lưu ý: Cần phân biệt rõ sự khác nhau giữa 2 con trỏ kclass và super

    class A
    end

Đoạn code trên sẽ sinh ra các cấu trúc dữ liệu trong bộ nhớ như sau:

Capture1.png Một ví dụ khác:

    class B < A
    end

Capture2.png

    obj = B.new

Capture4.png

2.Method Lookup

Một khi chúng ta đã hiểu được cấu trúc dữ liệu của một đối tượng trong Ruby thì quá trình tìm kiếm method của một đối tượng dường như là khá đơn giản và dễ hiểu, khi một Object gọi method quá trình đó diễn ra theo các bước sau:

  • Ruby sẽ lần theo con trỏ kclass của Object để tìm kiếm method đó trong bảng m_tbl của class mà con trỏ kclass trỏ đến
  • Nếu không có method nào được tìm thấy, Ruby sẽ tiếp tục lần theo con trỏ super của class này và tìm kiếm method trong bảng m_tbl của superclass
  • Quá trình lần theo con trỏ super này tiếp diễn cho đến khi con trỏ super nhận giã trị nil hoặc không tồn tại
  • Nếu method không được tìm thấy ở bất ký đối tượng nào, Ruby sẽ gọi method method_missing của Object đã trực tiếp gọi method. Quá trình này tiếp diễn một lần nữa đối với việc tìm kiếm method_missing (lưu ý giờ không phải là method ban đầu nữa )

3. Sơ đồ kế thừa của Ruby

Capture3.png

4. Đa kế thừa trong Ruby

Ruby không cho phép một class đa kế thừa từ nhiều class khác, Ruby dùng cơ chế Mix-in để mix-in các module lại, điều này giúp Ruby giải quyết vấn đề đa kế thừa

Trước tiên chúng ta sẽ tìm hiểu qua về Mix-in

  • Mix-in là một cơ chế cho phép multi- inheritance
  • Mix-in làm tăng khả năng tái sử dụng code và giải quyết được vấn đế “diamond problem” trong multi-inheritance
  • Mix-in có thể xem như interface trong các ngôn ngữ C#, Java… chỉ có điều các method của nó đã được implement
module Mixin
  def mixed_method
         puts “Hello from mixin”
  end
end

class A
include Mixin
end

Capture51.png

Giải thích: Mixin nằm trong hình chữ nhât nét đứt là một proxy class được tự động sinh ra trong quá trình mix-in, nó cũng chứa các con trỏ trỏ đến bảng iv_tbl and m_tbl giống như module Mixin gốc vậy, hay nói cách khác nó là bản sao của module Mixin gốc, ở đây chúng ta cần đặt câu hỏi tại sao lại phải sinh ra một proxy class mà không chèn trực tiếp module Mixin gốc, lý do là vì mỗi module chỉ có một con trỏ super nên nếu module Mixin gốc được chèn trực tiếp vào thì nó không thể trỏ đến một lớp superclass thứ 2 (trong trường hợp có một class hay module khác kế thừa từ nó)

Ruby giải quyết được vấn đề “diamond problem” trong đa kế thừa

Capture6.png

module B
    include A
   def helloHello from Bend
end

module C
    include A
    def helloHello from Cend
end

class D
include B
include C
end
D.new.hello # => “Hello from C”

Nếu chúng ta thay đổi thứ tự include thì kết quả sẽ thay đổi tương ứng

class D
include C
include B
end
D.new.hello # => “Hello from B

Cứ module nào được include sau sẽ được tìm kiếm method của module đó trước, đó là điều giải thích vì sao không diễn ra quá trình nhập nhằng tìm kiếm method trong 2 module B và

5. Eigen class (Đọc thêm)


All Rights Reserved