12/08/2018, 12:10

Object Model in Ruby

Như các bạn đã biết Ruby là một ngôn ngữ lâp trình theo hướng đối tượng, để làm viêc tôt với ruby chúng ta cần hiểu rõ hơn đối tượng trong ruby bao gôm những đặc điêm gì, có gì khác so với các ngôn ngữ lập trình hướng đối tượng khác và trong phần này chúng ta sẽ đi nghiên cứu về đối tượng trong ...

Như các bạn đã biết Ruby là một ngôn ngữ lâp trình theo hướng đối tượng, để làm viêc tôt với ruby chúng ta cần hiểu rõ hơn đối tượng trong ruby bao gôm những đặc điêm gì, có gì khác so với các ngôn ngữ lập trình hướng đối tượng khác và trong phần này chúng ta sẽ đi nghiên cứu về đối tượng trong ngôn ngữ lâp trình ruby.

Để bắt đâu, chúng ta mở irb khai báo một class với một phương thức như ở dưới đây

class TestClass
  def write_text
    @demo = 'test'
  end

  def input
    @input_data = 'input data'
    @demo = 'test 1'
  end
end

obj = TestClass.new
obj.class

ở trên chúng ta đã tạo một đối tượng obj cho class TestClass, vậy trong obj sẽ có những gì.

Instance Variables

Trong một đối tượng chúng ta sẽ có các biên instance variables(các biến thực thể), chúng ta có thể liệt kê hết các biến trong một đối tượng qua phương thức instance_variables

obj.write_text
obj.instance_variables # => [:@demo]

trong lệnh trên, để có thể liệt kê ra các instance variables, chúng ta phải gọi phương thức write_text() trước rùi mới gọi instance_variables(), điều này xảy ra bởi vi ruby không giống như các ngôn ngữ lâp trinh hướng đối tượng khác, trong Ruby không có sự kết nối giữa một lớp đối tượng với các biên thực thể , biên thực thê chỉ sẽ được hiên hữu khi được gán giá trị, chúng ta có thể hiểu tên và giá trị của biến thực thì như keys và values của một hash, chúng có thể khác nhau trong từng đối tượng,điều này giúp cho chúng ta có thế điều khiển được biến thực thể cũng như giá trị của chúng.

giả sử chúng ta khai báo một đối tượng là obj1 = TestClass.new và gọi phương thức là input() ta sẽ được

obj.input
obj.instance_variables # => [:@input_data, :@demo]

Methods

Ngoài biến thực thể instance variables, thì đối tượng cũng có các phương thức. chúng ta có thể lấy danh sách các methods có trong một đối tượng băng cách gọi Object#methods() giả sử ta lấy các methods của obj1 ở trên sẽ được

obj1.methods
 => [:write_text, :input, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Ngoài các phương thức cơ bản, chúng ta sẽ có thêm 2 phương thức write_text() và input() được khai báo trong class.

nếu chúng ta có thể pry, chúng ta có thể thấy đối tượng không thưc sự chứa các phương thức mà bên trong nó chỉ chứa các biến thực thể và một tham chiếu đến lớp của chính nó, như vậy các methods sẽ ở đâu. object.png

bởi vì các đối tượng đều chung một class cũng như các phương thức của class, do vây các phương thức điều phải chứa trong class. Nói chung, các biên thực thể thì được chứa trong đối tượng chính nó và các phương thức thì đươc chứa trong class của đối tượng, chính vì lẽ đó lên dù các đối tượng có các phương thức tương tự nhưng không thể chia sẻ các biến thực thể.

Class

Trong ngôn ngữ lập trình hương đối tương, mỗi một đối tương đều thuộc về một class nào đó. như vậy class là gì, trong ruby class chính là một đối tượng, lên nó cũng mang các đặc tinh của đối tượng.

"test".class # => String
String.class # => Class

và giông như đối tượng, class cũng có rất nhiều phương thức thuộc chính nó.

inherited = false
Class.instance_methods(inherited) # => [:superclass, :allocate, :new]

và nó cũng có superClass như của đối tượng

irb(main):135:0> String.superclass
=> Object
irb(main):136:0> Object.superclass
=> BasicObject
irb(main):137:0> BasicObject.superclass
=> nil

Theo trên ta có thể thấy superClass của một class là Object và Object có superClass là BasicObject, cốt lõi trong ruby.

Và tất cả các Class và Module đều có cấu trúc như vậy.

irb(main):1:0> Class.superclass
=> Module
irb(main):2:0> Module.superclass
=> Object

Class là một Module với việc thêm 3 phương thức cải biến new(), allocate(). và superclass() cho phép việc class có thể tạo ra các đối tượng, săp xếp các các lớp. và vì Class là một module lên tất cả những gì có thể áp dụng lên class thì có thể áp dụng lên module và ngược lại.

sơ đồ mối quan hệ giữa object, class và module sodo3.png

Gọi phương thức thức từ Object Từ một đối tượng để gọi một phương thức thì cần theo 2 bước:

  • Tìm phương thức, quá trình này gọi tới method lookup
  • Chạy phương thức, quá trinh này Ruby cần một vài thứ để gọi self

1. Tìm phương thức(method lookup)

Để có thể hiểu rõ quá trình method lookup chúng ta cần biết rõ 2 khái niệm receiver và ancestors chain

  • Receiver: đơn giản là đối tượng đang gọi phương thức
  • ancestors chain để hiểu ancestors chain chúng ta có thể nhìn vào mọi lớp của ruby, sau đó nhìn vào lớp cha của nó , sau đó là cha của cha nó...cứ như vậy chúng ta sẽ đến Object(lớp cha mặc đinh của class) và cuối cùng là BasicObject, đường dẫn đi qua các lớp như vậy gọi làancestors chain

Như vậy quá trình method lookup là quá trình tìm một phương thức đang gọi, ruby đi từ lớp hiện tại đến các lớp cha của nó cho đến khi tìm được phương thức cần tìm.

2. Thực thi method

Với phương thức đã tìm được trong quá trình method lookup, ruby sẽ thực thi method. Đôi tương hiện tại, hay là đối tương đang gọi method sẽ trở thành self, tất cả các instance variables của nó sẽ trở thành instance variables của self.

class TestClass
  def test
    @var = 'input'
    add_string()
  end
  def add_string
    @var = @var + " text"
    prinf @var
  end
end
irb(main):024:0> obj = TestClass.new
=> #<TestClass:0x00000001d52860>
irb(main):025:0> obj.test
=> 'input text'

Và ngoài ra nếu như phương thức chúng ta gọi mà không tồn tại, thì ruby sẽ mặc định gọi đến một phương thức là method_missing() và chỉ ra lỗi mà chúng ta đang gặp phải.

rb(main):001> obj.test_method
NoMethodError: undefined method `test_method' for #<TestClass:0x00000001d511 @var="input text">

Kernel

Trong ruby luôn tồn tại một số phương thức mà chúng ta có thể gọi mọi nơi trong code như prinf(), những phương thức như vậy được gọi là những instance variables của một module tên là Kernel. tree.png Những phương thức nằm trong kernel có thể được gọi từ mọi nơi và nếu như có phương thức nào được thêm vào kernel thì nó cũng thể được gọi ở mọi nơi.

0