12/08/2018, 18:00

Phân biệt class method và instance method trong ruby

Chắc hẳn một ruby newbie nào cũng đã từng gặp phải cú pháp self.method_name, khi đó chắc các bạn sẽ có một thắc mắc không biết là method này là dạng gì nhỉ. Sau đây mình xin chia sẻ với các bạn về hai method mà chúng ta dùng rất nhiều trong ngôn ruby đó là class method và instance method. Class ...

Chắc hẳn một ruby newbie nào cũng đã từng gặp phải cú pháp self.method_name, khi đó chắc các bạn sẽ có một thắc mắc không biết là method này là dạng gì nhỉ. Sau đây mình xin chia sẻ với các bạn về hai method mà chúng ta dùng rất nhiều trong ngôn ruby đó là class method và instance method.

Class method là method mà được gọi trên một lớp, còn instance method là method mà được gọi trên thể hiện của một lớp. Sau đây ta sẽ có một ví dụ nhanh và sau đó sẽ đi vào chi tiết để hiểu rõ hơn về từng method.

class Foo
  def self.bar
    puts 'class method'
  end
  
  def baz
    puts 'instance method'
  end
end

Foo.bar # => "class method"
Foo.baz # => NoMethodError: undefined method ‘baz’ for Foo:Class

Foo.new.baz # => instance method
Foo.new.bar # => NoMethodError: undefined method ‘bar’ for #<Foo:0x1e820>

Qua ví dụ đơn giản trên, ta thấy sự khác biệt giữa 2 phương thức bar và baz. bar là một class method nên khi ta gọi Foo.bar thì nó hoạt động tốt nhưng baz lại là một instance method dó đó khi ta gọi Foo.baz thì lập tức ruby sẽ bắn ra một exception là NoMethodError.

Tiếp theo ta sẽ gọi hai method trên trên một thể hiện của lớp (Foo.new) thì ta sẽ thấy kết quả ngược lại với khi ta gọi chúng ngay trên lớp đó.

Bây giờ bạn đã có một kiến thức nên tảng về hai phương thức class method và instance method. Sau đây tôi sẽ giới thiệu thêm về cách mà bạn có thể định nghĩa và sử dụng class method và instance method.

Ruby rất linh hoạt cho phép chúng ta định nghĩa class method bằng nhiều cách khác nhau. Sau đây là ví dụ về các cách mà chúng ta thường dùng:

# Way 1
class Foo
  def self.bar
    puts 'class method'
  end
end

Foo.bar # "class method"

# Way 2
class Foo
  class << self
    def bar
      puts 'class method'
    end
  end
end

Foo.bar # "class method"

# Way 3
class Foo; end
def Foo.bar
  puts 'class method'
end

Foo.bar # "class method"

Cách thứ 1 là cách mà tôi hay dùng nhất. Khi tôi thấy self.method_name ngay lập tức tôi có thể biết đây là một class method.

Cách thứ 2 là cách mà rất nhiều người sử dụng trong rails, nhưng nó có một hạn chế là khi bạn có một lớp mà có rất nhiều class method trong khối class << self, khi đó rất khó để phân biệt một method là class method hay instance method bởi vì nó được định nghĩa giống nhau (def bar).

Cách 3 là cách ít được dùng nhất, 3 cách trên không phải là 3 cách duy nhất được dùng để định nghĩa class method, nhưng chúng dường như là ba cách phổ biến nhất mà chúng ta thường gặp. Class method dùng cho bất kì hành động nào mà không xử lí các thể hiện của một lớp. ActiveRecord::Base # find là một ví dụ

module ActiveRecord
  class Base
    # some stuff
    class << self
      def find(...)
        # blah
      end
    end
  end
end

Một số cách sử dụng khác cuả class method trong rails là xác nhận hợp lệ và các liên kết trong ActiveRecord.

module ActiveRecord
  class Base
    def self.validates_presence_of(...)
      # make sure present
    end
  end
end

class Foo < ActiveRecord::Base
  validates_presence_of :bar
end

Khi bạn gọi validates_presence_of thì class method trong AR::Base là hàm được gọi.

Instance thì đơn giản hơn class method, dưới đây là các cách định nghĩa phổ biến của instance method

# Way 1
class Foo
  def baz
    puts 'instance method'
  end
end

Foo.new.baz # "instance method"

# Way 2
class Foo
  attr_accessor :baz
end

foo = Foo.new
foo.baz = 'instance method'
puts foo.baz

# Way 3
class Foo; end

foo = Foo.new
def foo.bar
  puts 'instance method'
end

Foo.new.baz # "instance method"

Sự khác biệt chính là các instance method chỉ làm việc trên một thể hiện của một lớp, do đó bạn phải tạo ra một thể hiện của các lớp để sử dụng chúng (Foo.new).

Class method chỉ có thể được gọi trên các lớp còn instance method chỉ có thể được gọi trên một thể hiện của một lớp. Rất mong bài viết này có thể giúp ích được cho các bạn!

0