12/08/2018, 17:54

So sánh các class level accessor trong Ruby on Rails

attr_accessor là sự kết hơp giữa attr_reader và attr_writer, nó là một marco rất hữu ích cung cấp getter và setter cho một instance variable. Nhưng đôi khi bạn muốn đạt được hiệu quả tương tự với các class variable. Có ít nhất ba cách để chúng ta có thể giải quyết vấn đề này là: attr_accessor, ...

attr_accessor là sự kết hơp giữa attr_reader và attr_writer, nó là một marco rất hữu ích cung cấp getter và setter cho một instance variable. Nhưng đôi khi bạn muốn đạt được hiệu quả tương tự với các class variable. Có ít nhất ba cách để chúng ta có thể giải quyết vấn đề này là: attr_accessor, cattr_accessor và class_attribute. Về cơ bản thì 3 cách trên hoạt động tương tự nhau nếu chúng ta không sử dụng kế thừa, nhưng nếu chúng ta sử dụng kế thừa thì chúng sẽ có những khác biệt đáng kể.

attr_accessor

Bạn sử dụng att_accessor trong trường hợp không muốn giá trị bị kế thừa. Trong trường hợp này, chúng ta tận dụng lợi thế thông thường của attr_accessor nhưng ở mức độ class. Sử dụng attr_accessor cho phép chúng ta định nghĩa các biến cho mỗi class con, nhưng giá trị của chúng không được kế thừa nếu được set ở class cha. Với mỗi class con giá trị của attribute được set là nil khi khởi tạo.

class Parent
 class << self
   attr_accessor :foo
 end
end

class Child < Parent 
end

Parent.foo = 100
Child.foo #=> nil // Giá trị không được kế thừa từ Parent

Child.foo = 200
Child.foo #=> 200
Parent.foo #=> 100 //Thay đổi giá trị ở class con không làm thay đổi giá trị ở class cha

cattr_accessor

Bạn sử dụng cattr_accessor khi muốn giá trị được chia sẻ ở trên tất cả các class. Trong trường hợp này, chúng ta sử dụng cattr_accessor để kế thừa giá trị của biến từ class cha cho các class con. Không cần thiết chúng ta phải khai báo cattr_accessor trong block class << self. Điều quan trọng cần lưu ý ở đây là việc định nghĩa lại giá trị của biến ở các class con sẽ thay đổi ở các class con khác và class cha.

class Parent
  cattr_accessor :foo
end
class Child < Parent
end
class Grandchild < Child
end

Parent.foo = 100
Child.foo #=> 100 // Giá trị được kế thừa

Child.foo = 200
Child.foo #=> 200
Parent.foo #=> 200 // Giá trị được thay đổi
Grandchild.foo #=> 200 // Giá trị được thay đổi

Grandchild.foo = 300
Parent.foo #=> 200 // Giá trị được thay đổi
Grandchild.foo #=> 200 // Giá trị được thay đổi

class_attribute

Bạn sử dụng class_attribute khi bạn muốn giá trị của biến được kế thừa và ghi đè mà không ảnh hưởng đến các class cha. Đây có lẽ là trường hợp phổ biến nhất.

class Parent
  class_attribute :foo
end

class Child < Parent
end

class Grandchild < Child
end

Parent.foo = 100
Child.foo #=> 100 // Giá trị được kế thừa

Child.foo = 200 
Child.foo #=> 200
Parent.foo #=> 100 // Thay đổi giá trị không anh hưởng đến class cha
Grandchild.foo #=> 200 // Thay đổi giá trị không anh hưởng đến class con

0