Class Definitions trong ruby
Bài đăng này đã không được cập nhật trong 8 năm
Trong phần này chúng ta sẽ đi tìm hiểu thêm về class trong ruby, rõ hơn là việc định nghĩa các lớp trong ngôn ngữ lập trình hướng đôi tượng ruby.
Việc định nghĩa các lớp trong ruby khác so với các ngôn ngữ lập trình hướng đối tượng khác như Java, C#. Khi chúng ta sử dụng từ khoá class, chúng ta không đưa mệnh lệnh nào cho các đối tượng sẽ được thực hiên trong tương lai. mà thực tế là chúng ta đang chạy code.
Inside Class Definitions
Trong một class chúng ta có thể viết bất kì dòng code nào khi định nghĩa class
class MyClass
puts 'Hello!'
end
=> Hello!
giá trị được trả về trong một class sẽ là dòng lệnh cuối cùng được thực hiện trong class, cũng tương tư như trong một block hay một phương thức.
result = class MyClass
self
end
=> MyClass
Ví dụ này nhấn mạnh môt điểm, trong một định nghĩa lớp(hoặc module), thì self ở đây cũng chính là bản thân class đó. Như vậy có thể hiểu những class và module cũng chỉ là những đối tượng.
The Current Class
Trong ruby, chúng ta luôn có một đối tượng hiện tại gọi là self. Tương tự, chúng ta cũng luôn có một class hiện tại hay modul hiện tại. Khi chúng ta định nghĩa một phương thức, phương thức đó sẽ trở thành instance method của lớp hiện tại.
Tuy chúng ta có thể lấy ra một tham chiếu đến đối tượng hiện tại thông qua self
, nhưng chúng ta sẽ không có từ khoá để tham chiếu đến lớp hay modul hiện tại.
Tuy nhiên, chúng ta có thể mở một class với từ khóa là class (hoặc module), thì lúc đó class sẽ trở thành class hiện tại
class MyClass
# The current class is now MyClass...
def my_method
# ...so this is an instance method of MyClass
end
end
Nhưng từ khoá class ở đây cũng có một hạn chế là phải cần tên chính xác của class chúng ta muốn mở. Khi muốn mở một class mà chúng ta không biết tên, chúng ta cần thay đổi class hiện tại bằng phương thức class_eval().
class_eval()
Module#class_eval()
sẽ ước lượng các nội dung đã tồn tại trong class
def add_method_to(a_class)
a_class.class_eval do
def m; 'Hello!' ; end
end
end
add_method_to String
"abc".m # => "Hello!"
Trong trường hợp mà bạn đang thắc mắc, Module#class_eval()
là rất khác biệt so với Object#instance_eval()
mà chúng ta đã học ở phần trước đó. instance_eval()
chỉ có thể thay đổi self, trong khi class_eval()
có thể thay đổi cả self
và class hiện tại. Với việc thay đổi class hiện tại, class_eval()
có hiệu quả giống như việc mở lại class, giống như từ khoá class
.
Module#class_eval()
thực sự lịch hoạt hơn class. Chúng ta có thể dùng class_eval
trên một biến bất kì để tham chiếu đên lớp, trong khi class yêu cầu một hằng số. Ngoài ra class sẽ mở một trường hợp mới sẽ làm thay đổi các trường hợp hiện tại, trong khi class_eval() là một Flat scope.
Vậy là chúng ta đã hoc đươc một vài điều mới về định nghĩa lớp
- Khi định nghĩa lớp, đối tượng hiện tại
self
là các lớp con được định nghĩa. - Bộ thông dịch của ruby luôn giữ một tham chiếu đến các lớp hoặc các modul hiện tại. Tất cả các phương thức đã đươc định nghĩa sẽ trở thành phương thức của lớp hiện tại.
- Trong định nghĩa lớp, các lớp hiện tại cũng giông như các lớp được xác định.
- Nếu chúng ta có một tham chiếu đến một class, chúng ta có thể mở class đó với phương thức class_eval().
Class Instance Variables
Trong ruby, tất cả các biến được coi đều thuộc về đối tượng hiện tại, và điều này cũng đúng với lớp định nghĩa.
xét ví dụ sau
class MyClass
@my_var = 1
def self.read; @my_var; end
def write; @my_var = 2; end
def read; @my_var; end
end
obj = MyClass.new
obj.write
obj.read # => 2
MyClass.read # => 1
ở ví dụ trên chúng ta đã khai báo 2 biến thực thể, cả 2 đều có tên là @my_var, nhưng chúng được khai báo trong các trường hợp khác nhau, và thuộc về đối tượng khác nhau. Bởi vì lớp cũng được coi là một đối tượng, và bạn có thể theo dõi self thông qua chương trình.
Một biến @my_var được định nghĩa với obj là self, do vậy nó là một biến thực thể của đối tượng obj. Biến @my_var khác được định nghĩa với MyClass là self, vì thế nó là một biến thực thể của đối tượng MyClass.
Singleton Methods
Ruby luôn cho phép chúng ta thêm một phương thức vào một đối tượng duy nhất, những phương thức như vậy được gọi là Singleton
str = "just a regular string"
def str.title?
self.upcase == self
end
str.title? # => false
str.methods.grep(/title?/) # => ["title?"]
str.singleton_methods # => ["title?"]
Việc thêm phương thức singleton chỉ áp dụng riêng cho đối tượng mà chúng ta thêm vào chứ không áp dụng cho tất cả đối tượng của class.
The Truth About Class Methods
Như chúng ta đã biết, các class là các đối tượng và tên các class đều là hằng số và cách thức gọi một phương thức trên một class cũng tương tự khi gọi một phương thức trên một đối tượng.
an_object.a_method
AClass.a_class_method
Chúng ta có thể thấy, việc gọi phương thức đều giống nhau về cấu trúc và nếu chúng ta dùng phương thức singleton
ở đây thì cũng được gọi như sau:
def obj.a_singleton_method; end
def MyClass.another_class_method; end
nếu như chúng ta đang viết code trong một định nghĩa lớp, chúng ta có thể dùng self
để thay thế cho tên của lớp.
class MyClass
def self.yet_another_class_method; end
end
và việc khai báo một phương thức `Singleton` cũng tương tự như vậy
```Ruby
def object.method
# Method body here
end
Aliases
Trong ruby, khi cần dùng một tên mới thay thế cho một phương thức đã tồn tại, chúng ta có thể sử dụng từ khoá 'alias'.
class MyClass
def my_method; 'my_method()' ; end
alias :m :my_method
end
obj = MyClass.new
obj.my_method # => "my_method()"
obj.m # => "my_method()"
trong alias
tên mới cho phương thức phải đứng đầu tiên, tên hiện tại đứng sau, và phải thêm dấu :
trước các tên.
Chúng ta phải chú ý rằng alias
là một từ khoá chứ không phải một phương thức nên chúng ta không cần bất kì dấu nào giữa 2 tên. Ruby cũng có phương thức Module#alias_method()
có chức năng tương tự như alias
class MyClass
alias_method :m2, :m
end
obj.m2 # => "my_method()"
All rights reserved