單例 ?vs 單一實例

單例 vs 單一實例

原文:Singleton vs. single instance


歡迎大家來到 Monologue,今天我們討論一個同程序設計相關的話題坛增,其不僅適用于 iOS 建椰,更適用于所有的程序開發(fā)雕欺。

雖然我并非是是程序設計方面的專家,但在個人看來棉姐,許多 app 項目對單例 / 單一實例的使用存在混淆不清的地方屠列,更可怕的是,開發(fā)者們似乎還沒有意識到伞矩。

因此笛洛,我想在這里同大家分享如何避免這樣的設計缺陷。如前所述乃坤,我并非程序設計方面的專家苛让,所以無法保證在這篇文章中所陳述的觀點100%正確,歡迎大家批評指正湿诊。我更傾向于讓將篇文章起到拋磚引玉的作用狱杰,引發(fā)討論,從而解決當前的問題厅须。所以仿畸,歡迎評論。


什么是“單例 vs 單一實例”

閑話少說朗和,直入正題:什么是“單例 vs 單一實例”

追根溯源

我已記不得誰是第一個如此描述這個問題的人错沽,但是我依然記得是從哪里讀到這個術語的。那是一本名叫《玩轉老舊代碼》的書(Working effectively with legacy code by Michael Feathers)眶拉。如果你不知道這它千埃,建議去讀讀。其中包含了許多有用的技巧忆植,即使你認為自己從不需要和老舊代碼打交道镰禾,依然可以從其中受益良多皿曲。

定義

“單例 vs 單一實例”表示一個很簡單的概念:當你使用單例的時候,先問問自己是否可以改用單一實例吴侦。

按照單例模式設計的類(以下簡稱單例類)在整個 app 中有且只有一個實例對象屋休,通常,在程序的任意地方都可以訪問它备韧。

相反劫樟,“單一實例”意味著類本身并非按照單例模式進行設計,但在使用時织堂,我們每次只使用一個實例對象叠艳。

乍看上去,好像沒什么大不了的易阳,我們甚至會覺得單例更棒更好用附较。其實不然,且聽我慢慢道來:

假象

封裝性

不管是單例還是單一實例潦俺,我們都只使用一個實例對象拒课。但是前者通過設計模式貫徹這一原則,后者僅僅依靠使用者主觀遵守這個原則事示。很明顯早像,在這種情況下,最好能夠對使用者進行強制約束肖爵,所以卢鹦,就封裝性來看,單例勝出劝堪。

易用性

開發(fā)者都是懶人(也應該是)冀自,喜歡簡單的接口。從這點上來講秒啦,單例無人能及熬粗。只需要引入頭文件(Swift 不用),調用返回單例對象的類方法帝蒿,就 OK 了。夠簡單吧巷怜?如果使用單一實例葛超,我們首先必須搞清楚誰擁有這個實例對象 & 如何能夠獲取到它。

不過延塑,好用并不總是好事绣张。說到這里,希望大家能夠有所警覺关带,我們繼續(xù)往下看侥涵。

進階

測試驅動開發(fā)

同許多《玩轉老舊代碼》探討的主題一樣沼撕,這個主題也提到了測試驅動開發(fā)(以下簡稱 TDD)。即使你反對測試驅動開發(fā)芜飘,也不著急關閉頁面务豺。

TDD 的關鍵在于各項測試獨立進行,程序環(huán)境在每次測試之間都會重置嗦明。此時笼沥,單例會造成麻煩:整個 app 的生命周期中有且僅有一個實例對象存在,我們無法保證這個對象是否還殘留有前一個測試的狀態(tài)信息(另外還需注意娶牌,許多 IDE 可以同時運行多個單元測試奔浅,它們之間的順序無法保證)。這個問題是可以解決的诗良,但總的來說汹桦,針對 TDD,“單例 vs 單一實例”之間較量為 0:1鉴裹。

限制訪問

同“易用性”相反舞骆,有時,我們必須限制對于某些對象的訪問壹罚。

嗯葛作,全局訪問有著天生的缺陷。如果在整個程序的任何地方都可以訪問一個對象猖凛,那么一旦出現(xiàn)問題赂蠢,就很難知道是誰進行了誤操作。試想一下找出一個被30個不同對象訪問的單例對象除了問題辨泳,這種 debug 極為麻煩虱岂。

另一個問題就是越好用的東西就越會被頻繁使用。這就會造成上一段文字討論的局面菠红,所有對象都肆意的調用單例第岖。

并不是說絕對不可以使用單例,從功能上來說這種方式?jīng)]問題试溯。但是它很容易被濫用(事實也是如此)蔑滓,例如下面的例子:


例子

就我個人而言,單例模式及其好用遇绞,但必須意識到我們正在濫用它键袱。如果你選擇使用它,請三思:是不是只能有一個實例對象摹闽;如果有兩個同時并存拜姿,就會破壞程序的結構屡谐?換句話來說,是不是一個對象就夠了荐吵?

最常見的濫用單例的典型:當我們需要一個全局變量時。許多現(xiàn)代編程語言都強調盡量避免使用全局變量,但在有時我們不得不用。我們創(chuàng)建一個單例對象,因為在哪里都可以引用它(同全局變量)谁不,試著回答上面的問題:

是不是只能有一個實例對象,或者說是不是一個對象就足夠了务蝠?

當然不是拍谐!

當然,上面只是舉了一個很基礎的例子馏段。想要觸及真正的問題轩拨, 就必須進一步深入挖掘。

以 MVC 架構中的控制器為例院喜,它是處理業(yè)務邏輯的地方亡蓉。我見過許多項目都在它們的業(yè)務邏輯中頻繁使用單例:CommunicatinManager,DataManager喷舀,NotificationMananger砍濒,LoginMananger等等。它們都不約而同的使用了單例硫麻,但問題是:有必要嗎爸邢?

拿 LoginMananger 來說,這個對象負責管理用戶登陸周期拿愧,其包含 token / cookie / credential 等信息杠河。

大多數(shù) app 一次只允許一個用戶登陸。所以浇辜,我們只一次只需要一個 LoginManager 實例對象券敌。乍一看來,單例完美無缺柳洋。但回到上面的問題:

是不是只能有一個實例對象待诅,或者說是不是一個對象就足夠了?

是的熊镣,沒錯卑雁。如果同時出現(xiàn)兩個 LoginManager 那就有問題了。等等绪囱,不覺得有點奇怪嗎测蹲?考慮下面的情況:

  • 登入
  • 登出
  • 再次登陸,但使用不同的證書

氨瞎俊弛房!雖然整個程序只需要一個 LoginMananger 實例對象道盏,但是這個其在程序運行的期間發(fā)生了變化而柑。所以文捶,上述問題可以修正為:

整個 app 的生命周期中,是不是只能有一個一成不變的實例對象媒咳?

對于單例模式來說粹排, LoginManager 對象在不同用戶登陸周期之間持續(xù)存在。因此涩澡,用戶登出時顽耳,這個對象必須清除其所保存的用戶信息。貌似簡單妙同,用戶的登陸狀態(tài)是通過若干項信息表示的-token射富,用戶名等≈嘀悖可以其他用戶相關數(shù)據(jù)胰耗,諸如緩存的好友列表,頭像芒涡,密碼呢柴灯?這些信息是很難維護的。你不能指望你的同事(甚至你自己)記得在登出時清除數(shù)據(jù)费尽。

某次赠群,如果你忘記清理用戶 token,會發(fā)生什么旱幼?用戶可能會以錯誤的身份能登陸查描!

如果 LoginMananger 對象不是一個單例,我們只需在用戶登出時刪除這個對象即可速警。完全不用擔心自己忘記清理數(shù)據(jù)叹誉。

同現(xiàn)實生活類似,在軟件中沒有什么是永恒的闷旧。所以別舍不得釋放你的對象长豁,否則難過的是你??。

好吧忙灼,今天的關于“單例 vs 單一實例”的討論就到這里匠襟,感謝閱讀??!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末该园,一起剝皮案震驚了整個濱河市酸舍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌里初,老刑警劉巖啃勉,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異双妨,居然都是意外死亡淮阐,警方通過查閱死者的電腦和手機叮阅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泣特,“玉大人浩姥,你說我怎么就攤上這事∽茨” “怎么了勒叠?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長膏孟。 經(jīng)常有香客問我眯分,道長,這世上最難降的妖魔是什么柒桑? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任颗搂,我火速辦了婚禮,結果婚禮上幕垦,老公的妹妹穿的比我還像新娘丢氢。我一直安慰自己,他們只是感情好先改,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布疚察。 她就那樣靜靜地躺著,像睡著了一般仇奶。 火紅的嫁衣襯著肌膚如雪貌嫡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天该溯,我揣著相機與錄音岛抄,去河邊找鬼。 笑死狈茉,一個胖子當著我的面吹牛夫椭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氯庆,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蹭秋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了堤撵?” 一聲冷哼從身側響起仁讨,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎实昨,沒想到半個月后洞豁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年丈挟,在試婚紗的時候發(fā)現(xiàn)自己被綠了闰挡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡礁哄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出溪北,到底是詐尸還是另有隱情桐绒,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布之拨,位于F島的核電站茉继,受9級特大地震影響,放射性物質發(fā)生泄漏蚀乔。R本人自食惡果不足惜烁竭,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吉挣。 院中可真熱鬧派撕,春花似錦、人聲如沸睬魂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氯哮。三九已至际跪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喉钢,已是汗流浹背姆打。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肠虽,地道東北人幔戏。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像税课,于是被迫代替她去往敵國和親评抚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理伯复,服務發(fā)現(xiàn)慨代,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 單例模式(SingletonPattern)一般被認為是最簡單啸如、最易理解的設計模式侍匙,也因為它的簡潔易懂,是項目中最...
    成熱了閱讀 4,253評論 4 34
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,145評論 25 707
  • 最近微信朋友圈偶然發(fā)現(xiàn)一些朋友默默對我設置了朋友圈對其不可見,屏幕上只留下一道黑線....插在了我幼小心靈里想暗,又要...
    黑姆閱讀 252評論 0 0
  • 有了自己的環(huán)境之后说莫,你需要去學習Salesforce的基本知識杨箭,概念,操作方法储狭,配置等互婿。 我們假定你從零開始學習S...
    愛寫作的項目經(jīng)理閱讀 3,978評論 2 5