0

Class Definitions trong ruby

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

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í