深入Rails3: ActiveSupport 的 class_attribute
来源:互联网 发布:春秋与战国的区别知乎 编辑:程序博客网 时间:2024/05/29 02:49
如果你對 Ruby Object Model 稍加認識,就會知道除了 class variable 和 instance variable 之外,還有一種變數叫做 class
instance variable,之前我在研究時有撰文解釋過,讀者可以複習一下。
在 Rails3 ActiveSupport Core Extension 中,就有幾個方法是在處理這件事情,讓我們可以很方便地定義存取方法,讓我們來看
看。
cattr_* 系列
Ruby 語言本身就有針對 instance variable 提供 attr_accessor, attr_reader, attr_writer 等方法,這些會建立 @ 開頭的實例變數並提
供存取方法。而 ActiveSupport 的這個擴充則是針對 class variable 也提供類似的功能,它會建立 @@ 開頭的類別變數及提供存取
方法。
class A cattr_accessor :xend class B < Aend A.x = 1A.x # => 1B.x = 2B.x # => 2A.x # => 2 跟著改了
注意到整個繼承體系 A, B 都共用了 @@x,所以如果改了 B.x,那也會連動 A.x。很多時候,這不是我們要的,例如在 Rails 中所有
Model 都繼承自 ActiveRecord,於是會共用 class variable,如果要各自 Model 需要有自己的 class 屬性就不合用了。所以說認識
class instance variable 可以說是寫 ActiveRecord Plugin 的必備知識 (甚至也有人說 Ruby 的 class variable 設計錯誤,當初就應該
把行為設計成 class instance variable 比較實用)
class_attribute
不像 class variable 整個繼承體系共用類別變數,class instance variable 是不同 class 分別獨立的,也就是類別 A 的 class instance
variable 和 B < A 的 class instance variable 是獨立的。
class A @x = 1endclass B < AendA.instance_eval { @x } # => 1B.instance_eval { @x } # => nil 因為跟 A 的 @x 是獨立的,不會繼承下來
這個特性讓我們可以實作出真正實用的行為,也就是 “屬性可以繼承,但是如果有修改,不會影響到 parent class 的值”。這就是
ActiveSupport 的 class_attribute 提供的功能:
class A class_attribute :xend class B < Aend A.x = 1B.x # => 1 繼承自 AB.x = 2B.x # => 2A.x # => 1 不變
最後的 A.x 還是保持本來的值不受影響。
不過使用上有個細節要注意:如果這個值是會變動的結構(物件),例如 Array 或 Hash,那麼 child class 第一次使用時就不適合用 in-
place 類型的方法,例如:
A.x = []B.x << :fooA.x # => [:foo] 也跟著改了,不對啊啊啊!!B.x # => [:foo]
要改成用 setter 類型的方法:
A.x = []B.x += :foo # 第一次設定必須使用 setter 類型的方法A.x # => [] 不變B.x # => [:foo]B.x << :barA.x # => []B.x # => [:foo,:bar]
會造成這種行為的原因是,ActiveSupport 並不是複製 A.x 給 B.x,而是如果 B.x 沒設定,就去讀 A.x (這點跟下述的
class_inheritable_* 用複製的作法就不同) 。
ActiveSupport cattr_* 還提供了 query 是否為 nil 的方法,也就是 A.x? 和 B.x?
最後,ActiveSupport cattr_* 的行為也適用於實例化時,不會影響到 parent class:
A.x = 1object = A.newobject.x = 2 object.x # => 2A.x # => 1 保持不變
class_inheritable_* 系列
ActiveSupport 還有一套古早的 class_inheritable_* 方法,它的作用跟上述的 class_attribute 是差不多的,只是內部的實作不同。是
說 class_attribute 是 Rails3 才新寫的,效能較佳,會留著 class_inheritable_* 主要是因為向下相容性(有很多的 Plugins 使用了這個
方法)。
- 深入Rails3: ActiveSupport 的 class_attribute
- Rails3深入理解routes之一 - routes的目的
- 强大的 ActiveSupport::Notifications
- [ROR] ActiveSupport::Callbacks的使用
- Rails3的部署问题
- 单独使用ActiveSupport的助记
- Rails3: 新的 Metal 機制
- Rails3深入理解routes之二 - 资源routes(rails默认)
- 42个有用的rails3链接
- rails3 数据 migration 之一 - migration 的解析
- rails3.2 中的 carrierwave 的快速开发
- 改善Rails3中render json的性能
- [Ruby On Rails]Rails中的ActiveSupport::Callbacks的使用
- rails3.0.5 连接MySQL5.1需要注意的问题
- Rails3入门之十一 建立一个多模型的form
- Rails3入门之十二 视图的帮助程序
- 用一堆Gem来架起你的Rails3机枪
- Rails3.2 下使用 plugin出现的问题
- java设计模式--工厂模式
- 通过Terminal安装VMware Tools
- 找零钱问题
- OC内存管理(非ARC)
- 一道阿里巴巴面试题求解答
- 深入Rails3: ActiveSupport 的 class_attribute
- This is only a manuscript of libsvm experiment
- cordova跳转到js界面黑屏
- MyEclipse 2015中添加Tomcat服务器
- 最优装载
- Linux学习笔记(二)——ubuntu下如何切换到root登陆
- 关于quartz的并发问题
- 关于GDI资源使用后未释放,导致GDI对象猛增,程序花屏,异常退出的问题
- UITextView控件的用法详解