1.橫向查找
今天主要簡單講講Ruby對象模型,說簡單它也是比較簡單的--只要知道在Ruby里面一切都是對象。說難,它確實跟其他語言有那么點不一樣。這里簡單講講,我們看下面的代碼。
[1] pry(main)> a = "lanzhiheng"
=> "lanzhiheng"
[2] pry(main)> a.class
=> String
[3] pry(main)> a.class.class
=> Class
[4] pry(main)> a.class.class.class
=> Class
這堆語法應該很熟悉吧。這里我創建一個字符串"lanzhiheng"
并賦值給a
。這里a
是String
類型的一個實例。而String
類型又是Class
類型的一個實例,用中文說就是類類型
的一個實例。而類類型
又是類類型
的一個實例。所以類類型
(Class類型)應該是"最原始"的類型了。我們姑且把這種方式稱作橫向查找。我們通過每個對象的class
屬性來找到它所屬的類型。
2.縱向查找
有橫向查找當然就會有縱向查找,Ruby中我們通過superclass
屬性來查找一個類的父類,我們可以看下面這個運行結果。
[18] pry(main)> a = "lanzhiheng"
=> "lanzhiheng"
[19] pry(main)> a.superclass
NoMethodError: undefined method `superclass' for "lanzhiheng":String
from (pry):19:in `__pry__'
[20] pry(main)> a.class
=> String
[21] pry(main)> a.class.superclass
=> Object
[22] pry(main)> a.class.superclass.superclass
=> BasicObject
[23] pry(main)> a.class.superclass.superclass.superclass
=> nil
這個訪問鏈是不是很熟悉?由于a
只是一個普通的對象,它沒有父類所以這里通過訪問它的superclass
屬性會報錯。然后我們通過繼承鏈訪問String
的父類。發現結果是這樣的String -> Object -> BasicObject
。好了,到這里就好了。因為這個BaseObject
是最基本的類了,所有的類都繼承自它。不過開發里面用得比較多的還是Object
類,它包含的基本方法比BasicObject
要多得多。這種尋找父類的方式我們姑且叫做縱向查找。一步一步向上搜索它的祖先。
難道要獲取一個對象的祖先鏈就必須要這樣嗎?當然不是,肯定有更簡單的辦法。
[34] pry(main)> a.class.ancestors
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
這個可以獲取所有的String類型
的祖先類(包括它自己)。但是不對啊,明顯多了一些東西!!!多出來的東西叫做Module
。可以用于類的擴展,Ruby On Rails
這個框架里面就用了很多這種東西。不過今天討論的是類,這里先不多說。因為模塊并不是我們所需要的類類型
。所以我們可以這樣把它去掉。
[35] pry(main)> a.class.ancestors.select {|item| item.is_a?(Class) }
=> [String, Object, BasicObject]
我們通過獲取到祖先后,通過select
來篩選掉不需要的Module
。其實這只是權宜之計,不妨再多說一點:
[38] pry(main)> Class.superclass
=> Module
[40] pry(main)> Module.class
=> Class
其實Module
類是類類型
的父類,而Module
同時又是類類型
的實例。這是個比較古怪的事情。不過這說明我們不能以同樣的方法來篩選Module
。
[41] pry(main)> a.class.ancestors.select {|item| item.is_a?(Module) }
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
String類型
的整條祖先鏈其實都是Module
。不過由于屬于Class
卻不一定是Module
所以我們姑且先這樣做著吧。
3.單件方法
傳統編程中如果我想給一個對象增加方法,我們的做法是在該方法所屬的類或者其父類中定義需要的方法。而在Ruby里面我們可以更簡單地完成這個事情。通過單件方法我們可以直接綁定方法在單個對象中。看看下面這個例子:
a = "hello lan"
b = "hello world"
def a.goodbye; "good bye" end
運行結果
[57] pry(main)> a.goodbye
=> "good bye"
[58] pry(main)> b.goodbye
NoMethodError: undefined method `goodbye' for "hello world":String
from (pry):58:in `__pry__'
可見這個方法只綁定在了對象a
中,而在對象b
中卻沒有它的身影。這在一定程度上增加了程序的靈活性。我們為一個對象增加方法不再需要重新定義類的行為,而只需要綁定在相關的對象上即可,過不過癮?
4. 單件類
上面這些知識對于一般的開發來說基本上已經夠用了。當然這里提到單件類是想表示一下Ruby跟其他語言有些不同的地方。單件類也是類,只不過默認情況下Ruby把它隱藏起來了。
對于單件類,今天淺嘗一下,先看看它到底是什么
[62] pry(main)> a.singleton_class
=> #<Class:#<String:0x007fad3cd46cc8>>
[63] pry(main)> a.singleton_class.instance_methods.grep /good/
=> [:goodbye]
[64] pry(main)> a.singleton_class.class
=> Class
從上面可以看出單件類其實真的是一個類,雖然在繼承鏈中沒有給出來,但是,它確實是一個類。而且我們定義的單件方法goodbye
其實就是這個類中的實例方法。只是這個類的實例只有一個就是對象a
,因此就只有它能夠訪問這個方法了。而且我們貌似不能通過單件類來創建新的對象:
[70] pry(main)> k = a.singleton_class.new
TypeError: can't create instance of singleton class
from (pry):70:in `new'
我們就是通過定義單件類的實例方法來把方法綁定到了單件類對應的對象中去的。這是我覺得Ruby相當不錯的特性。
今天就到這吧。