KẾ THỪA TRONG RUBY
Bài đăng này đã không được cập nhật trong 3 năm
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:
Một ví dụ khác:
class B < A
end
obj = B.new
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
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
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
module B
include A
def hello
“Hello from B”
end
end
module C
include A
def hello
“Hello from C”
end
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