从自己实现Ruby单例模式揭秘Ruby模块内幕
???? 從自己實現Ruby單例模式揭秘Ruby模塊內幕
緣起
整個故事要從某一天開始說起,那天,我看到一篇文章介紹了Ruby中實現單例模式的模塊。Singleton模塊,只要include? Singleton模塊,就可以為一個Ruby類添加單例功能。
我頗為驚奇,于是查看Singleton.rb源碼,洋洋灑灑幾百行,看不懂。做技術的都知道,遇到不理解的東西我們總是想探究清楚,否則必茶不思飯不想,夜不能寐。
于是,我就想到CSDN論壇問問Ruby高人,不料Ruby論壇總是系統維護中這個狀態,想到其他Ruby社區問問,但一想還是算了。我平常都不逛其他社區的。
于是,繼續鉆研,費了一晚上的時間,終有所獲。雖然沒有完全看懂Ruby核心庫中的Singleton模塊的源碼,但自己也鼓搗出了一個Singleton模塊出來。
并且對Ruby模塊和Ruby語言的本質有了更深的認識。
?
?
?
使用模塊類載入方法實現的單例模塊!
源代碼:
下面請大家直接看看我的簡單版的Singleton模塊的源代碼。
?
??? 單例模塊,存在的意義就是在模塊被載入類時,給類添加類方法和創建對象實例等
module?? Singleton
這個方法在模塊被載入類時調用,傳入的參數是? 類對象
def self.included(base)??
這個操作把另一個模塊直接添加到Class對象上。類對象上的方法就是類方法。
盡管模塊中的方法是模塊的實例方法。
??? base.extend(SingletonClass);
?????
??????? puts("Singleton? Include!");
創建類的實例,然后把類的new方法設為私有類方法,防止被調用
最后把類的實例存放到類的方法中。
??????? myInstance=base.new();
?? base.private_class_method :new
????? # private_class_method :new
??? base.setClass(myInstance);
??????
??????
?????? #createSingleton(base);
??????
??????
?
???? end
???
??????
?????? end
????
?? module? SingletonClass
這個模塊附加上去的類方法,把類實例保存在模塊的實例變量中。也就是目標類的類變量中。
??? def setClass(base)
??????? puts("setClass");
??????? @myClass=base;
???????
??????? return? @myClass;
????? end
???? 單例方法,僅僅返回類的保護實例變量。
?????? def instance()
??????? puts("instance");
??????
???????
??????? return? @myClass;
????? end
?
? end
?
?
?
class Test
?? include Singleton;
?#private_class_method :new
?????
? def say(val)
????? puts(val);
??? end
?
end
?
test=Test.instance();
test.say("sssssss");
#test=Test.new();? # fail
?
?
技術詳解
上面展示的Singleton模塊的源代碼,雖然代碼量不多,卻使用了很多Ruby的高級技術。很有教學意義。當然,如果直接拿去使用也沒有問題,雖然沒有官方的Singleton模塊功能強,卻一樣實現了單例模式。
?
通過模塊怎樣給類添加類方法
Singleton模塊的功能是,目標類通過
include Singleton;
這一行代碼,可以給自己的類添加一個類方法instance().
我們一般使用Module,是給Module定義一些實例方法,然后這些方法就會成為目標類的實例方法。
我們也可以給Module定義類方法。這些方法必須要通過
Module.方法名()調用。
試驗下來,我們發現,目標類上不能調用模塊的方法。
?
那怎么才能實現通過Module給目標類添加類方法呢?
?
我們知道,Ruby中類是類,但其實類也是一個對象,一個特殊的對象。
Ruby的類對象就是Class類的實例。因此,對象具有的所有特征,類對象也都有。
Java,JS,C#都是如此的。
?
Ruby的類對象上的實例方法,不就是類的方法嗎?
鑒于此,我們想到,只要在類對象上添加實例方法,那么我們就可以給類添加類方法。
?
而Ruby和JavaScript一樣,都可以給對象而不是類型動態添加方法。這樣就成了。
?
Ruby的類繼承體系
?????????? ObjectClass
???????? ……
????? BaseClass
????????? ^
????????? |
(SingletonClass)
???????? ^
???????? |???? 各個include的Module
?????? SomeClass
???????? ^????
???????? |
???? (SingletonClass)
???????? ^
???????? |
???? someObj
?
?
上面就是Ruby的繼承體系,獨特而又精妙。
Ruby可以實現動態增刪對象的成員,而不僅僅是動態增刪類的成員。
另一種具備此種神功的就是JavaScript。但是,Ruby內部實現這些強大功能的內部機制和JavaScript的機制是截然不同的。
可謂殊途同歸!
?
?
1,Ruby是單根結構的單繼承體系的語言,它的根基類是Object類。所有的類最后都繼承Object類,這和其他語言一樣。Java,C#,JavaScript,SmallTalk等都是如此。
?
2,Ruby的類可以包括多個模塊。通過
include ModuleName
?? 即可達到此種目的,這種技術叫做混入Mixin。
?? 通過這種技術,使單繼承的Ruby達到了多繼承的效果。
??? JavaScript也可以實現混入Mixin技術。這個我以后有時間再說。
?
在方法查找時,是先查找類本身定義的方法,然后再查找引入的模塊中的方法。最后查找基類的方法。
?
3,Ruby不僅可以使用反射技術實現動態增刪類型的成員,還可以動態增刪對象的成員。
也就是說,Ruby類的各個實例,可以在運行時具備完全不同的數據結構和方法、行為特征!
這種強大的特性,JavaScript也具備。
現在讓我們看看Ruby是怎樣做到這一點的。
Ruby的每一個類實例,都有一個單獨的特殊的類型,SingletonClass。
??? (SingletonClass)
???????? ^
???????? |
???? someObj
?
注意,SingletonClass不是Singleton模塊,不是用于實現單例模式的那個冬冬。
Ruby的一個特殊特征就是,一切都是類。JavaScript的哲學是一切都是對象。
既然任何對象都從屬于一個唯一的類型,那么我們只要使用動態修改Ruby類的成員的技術修改這個SingletonClass的成員,就可以實現動態修改單個對象的成員了。
?
4,回到上面的Singleton模塊的例子,為什么我們要講Ruby動態修改單個對象的方法呢?因為我們要使用這種技術實現給Ruby的類增加類方法instance()。
再看上面的Ruby的繼承圖,我們看到Ruby的類,本身也是Class類型的一個實例。因此,任何類也都是有SingletonClass的。
因此,只要我們給類的SingletonClass增加實例方法instance,那么這個類就有了實例方法instance。這樣,我們的類就有了類方法instance。
上面,我們正是利用了Ruby的這一特性,通過模塊給目標類動態添加了類成員函數instance()。
?
5,模塊的included方法。
module?? Singleton
這個方法在模塊被載入類時調用,傳入的參數是? 類對象
def self.included(base)?
?
??? 模塊的included方法,會在模塊被類include時執行,其參數就是目標類對象。這個方法就是我們通過模塊類操作目標類的入口點。
?
1)給類的SingletonClass添加模塊,從而給目標類添加instance()方法。
盡管模塊中的方法是模塊的實例方法。
??? base.extend(SingletonClass);
?????
??????? puts("Singleton? Include!");
?
2)創建類的實例,然后把類的new方法設為私有類方法,防止被調用
最后把類的實例存放到類的方法中。
??????? myInstance=base.new();
?? base.private_class_method :new
???
??? 現在,沒有人能夠再創建目標類的實例了!
3)保存我們的單例。
?base.setClass(myInstance);
?base.private_class_method : setClass
?
?
4)看看我們給目標類添加靜態方法的模塊。
? module? SingletonClass
這個模塊附加上去的類方法,把類實例保存在模塊的實例變量中。也就是目標類的類變量中。
??? def setClass(base)
??????? puts("setClass");
??????? @myClass=base;
???????
??????? return? @myClass;
????? end
???? 單例方法,僅僅返回類的保護實例變量。
?????? def instance()
??????? puts("instance");
??????
???????
??????? return? @myClass;
????? end
?
?
OK!大功告成了!
下回也許我會再寫一篇文章,比較一下同樣NB的JavaScript和Ruby的優劣。
?
總結
以上是生活随笔為你收集整理的从自己实现Ruby单例模式揭秘Ruby模块内幕的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机膜怎么撕下来(钢化膜怎么撕下来)
- 下一篇: 「黑科技」智能防疫消毒机器人 技术方案介