+1

Module và thuật toán tìm kiếm method

Như bạn biết, Module rất giống với các Class trong ruby. Bạn có thể tạo ra một Module giống như bạn tạo ra một Class, bằng cách gõ từ khóa module và tiếp theo là một loạt các định nghĩa Method. Trong khi các Module tương tự như các Class, chúng được Ruby xử lý theo 3 cách quan trọng:

  • Ruby không cho phép bạn tạo ra một đối tượng trực tiếp từ Module. Trên thực tế, điều này có nghĩa là bạn không thể gọi method mới trên Module bởi vì method mới là của Class, chứ không phải của Module.
  • Ruby không cho phép chỉ định một Class cha cho một Module.
  • Ngoài ra bạn có thể include một Module vào một Class bằng cách sử dụng từ khóa include

Nhưng Module là gì? Liệu nó có sử dụng cấu trúc RModule? Bao gồm một Module và một Class.

Module là Class

Ruby cài đặt Module giống như Class. Khi bạn tạo ra một Module, Ruby sẽ tạo ra một cặp cấu trúc RClass/rb_classext_struct khác. giống như việc định tạo ra một Class mới. Ví dụ, giả sử chúng ta định nghĩa ra một Module như thế này.

module Professor
end

Ở bên trong, Ruby sẽ tạo ra một Class, chứ không phải một Module. Hãy nhìn vào hình dưới đây

Trong hình này, chúng ta nhìn thấy cấu trúc RClass (bạn có thể thao khảo tại đây) thêm một lần nữa. Tuy nhiên, tôi đã loại bỏ một số các giá trị từ diagram vì Module không sử dụng tất cả các thành phần. Quan trọng nhất, tôi đã xóa iv_index_tbl bởi vì bạn không thể tạo các đối tượng instance của Module, nói cách khác bạn không thể tạo mới method trên Module. Điều này có nghĩa là không có thuộc tính object-level, tôi cũng đã bỏ các giá trị refined_class và allocator bởi vì Module không sử dụng chúng. Tôi cũng đã bỏ con trỏ super bởi vì module đã có superclass, mặc dù bạn không cần phải khai báo. Một định nghĩa kỹ thuật của module Ruby (bây giờ bỏ qua giá trị origin) nó sẽ trông như thế này:

Một Module Ruby là một đối tượng Ruby chứa các định nghĩa method, một con trỏ superclass và một bảng constants.

Nhúng một Module vào một Class

Sự kỳ diệu đằng sau Module xảy ra khi bạn include vào Class

module Professor
end

Class Mathematician < Person
  include Prefessor
end

Ruby tạo ra một bản sao của cấu trúc RClass cho Module Professor và sử dụng nó như một superclass cho Mathematician. Mã nguồn của Ruby đề cập đến bản sao của Module này như một included class. Superclass của bản sao mới của Professor được đặt thành superclass gốc của Mathematician, có thể bảo vệ superclass hoặc chuỗi ancestor. Hình sau cho ta cái nhìn tổng quát về vấn đề rắc rối này

Bạn có thể thấy lớp Mathematician ở góc bên trên cùng bên trái. Ở bên dưới dọc theo bên trái, bạn sẽ nhìn thấy chuỗi superclass của nó: superclass của Mathematician là Person và có các superclass khác, ..vv.. Các con trỏ super của mỗi cấu trúc RClass chỉ xuống superclass kế tiếp. Bây giờ đến module Professor phía bên phải của hình vẽ. Khi chúng ta include module này vào trong lớp Mathematician, Ruby thay đổi con trỏ super của Mathematician để trỏ vào bản sao của Professor và con trỏ super của bản sao Professor trỏ vào Person, superclass gốc của Mathematician.

Thuật toán tìm kiếm Method của Ruby

Bất kể khi nào bạn gọi một phương thức, bất kể khi nào bạn "gửi một tin nhắn đến một người nhận", để sử dụng thuật ngữ lập trình hướng đối tượng, Ruby cần xác định lớp nào cài đặt method đó. Thỉnh thoảng điều này là hiển nhiên: Lớp của người nhận có thể cài đặt target method. Tuy nhiên đây không phải là các trường hợp thường xuyên xảy ra. Nó có thể là một số module hoặc class khác trong hệ thống của bạn cài đặt các method. Ruby sử dụng một thuật toán rất chính xác để tìm kiếm thông qua các module và các class trong chương trình của bạn theo thứ tự cụ thể để tìm kiếm target method. Sự hiểu biết này rất cần thiết cho các Developer vì vậy hãy xem xét kỹ hơn sơ đồ sau

Thuật toán này rất đơn giản phải không. Như bạn thấy, Ruby đơn giản theo các con trỏ super cho đến khi nó tìm thấy lớp hoặc module có chứa target method. Có thể bạn đang tưởng tượng rằng, Ruby sẽ phải phân biệt giữa module và class sử dụng một vài logic đặc biệt, nó có thể xử lý các trường hợp include nhiều module. Nhưng không, nó chỉ là một danh sách liên kết con trỏ super

Ví dụ về tìm kiếm một Method

Bây giờ, chúng ta sẽ tìm hiểu về thuật toán này. Đầu tiên, hãy xây dựng một ví dụ chúng ta sẽ sử dụng một class, một superclass và một module. Điều này cho phép chúng ta xem xét các class và các module làm việc cùng nhau như thế nào. Lớp Mathematician cùng với các phương thức accessor first_name và last_name

class Mathematician
  attr_accessor :first_name
  attr_accessor :last_name
end

Bây giờ, chúng ta hãy giới thiệu về một superclass. Chúng ta sẽ tạo lớp Person là superclass của Mathematician

class Person
end

class Mathematician
  attr_accessor :first_name
  attr_accessor :last_name
end

Chúng ta di chuyển tên các thuộc tính sang superclass Person bởi vì không chỉ các nhà toán học (mathematician) mới có tên. Cụ thể là

class Person
  attr_accessor :first_name
  attr_accessor :last_name
end

class Mathematician < Person
end

Cuối cùng chúng ta sẽ include module Professor vào lớp Mathematician

class Person
  attr_accessor :first_name
  attr_accessor :last_name
end

module Professor
  def lectures; end
end

class Mathematician < Person
  include Professor
end

Thuật toán tìm kiếm Method hoạt động như thế nào?

Bây giờ chúng ta đã tạo ra một ví dụ, chúng ta đã sẵn sàng để xem Ruby tìm kiếm một method mà chúng ta gọi. Mỗi khi chúng ta gọi bất kỳ method nào trong một chương trình của bạn, Ruby sẽ hoạt động theo một tiến trình mà chúng ta thấy ở đây. Để gọi một method. Chúng ta sẽ tạo một đối tượng mathematician và thiết lập first name của nó:

ramanujan = Mathematician.new
ramanujan.first_name = "Srinivasa"

Để thực thi mã này, Ruby cần tìm kiếm method first_name=. Method này ở đâu. Làm thế nào để Ruby tìm được nó một cách chính xác. Đầu tiên, Ruby sẽ tìm ra class từ đối tượng ramanujan thông qua con trỏ klass

Tiếp theo, Ruby kiểm tra xem liệu rằng lớp Mathematician có cài đặt trực tiếp first_name= bằng cách xem qua bảng method của nó

Bởi vì chúng ta đã di chuyển hết tất cả các method vào superclass Person, method first_name= sẽ không có ở trong class Mathematician. Ruby tiếp tục với thuật toán và tìm kiếm các superclass của Mathematician sử dụng con trỏ super.

Nhớ rằng, đây không phải là lớp Person, mà nó là lớp included, một bản sao của module Person. Bởi vì đó là bản sao, Ruby sẽ tìm qua bảng method của Professor. Professor cũng chứa một method lectures duy nhất. Ruby vẫn chưa thể tìm thấy phương thức first_name=. Bởi vì Ruby không tìm thấy first_name= trong Professor, nó vẫn tiếp tục tìm kiếm trên con trỏ super, nhưng lần này nó sử dụng con trỏ super trong lớp Professor

Lưu ý rằng, superclass của module Professor hay cụ thể hơn, superclass của bản sao included của module Professor là lớp Person. Đây cũng chính là superclass gốc của lớp Mathematician. Cuối cùng, Ruby đã thấy method first_name= trong bảng method của Person.

Kết luận

Bài viết này chỉ là dịch lại phần Class trong chương 6: Method lookup and Constant Lookup của của cuốn sách Ruby Under a Microscope Rất mong nhận được những lời đóng góp ý kiến của mọi người.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí