單件模式:隱式全局變量 vs. 顯式全局變量

全局變量究竟會被其他哪些函數訪問,會被哪些函數讀取或改寫。必須找出所有讀寫該全局變量的代碼,理解這些函數的操作流程,才能充分了解當前函數的功能以及函數之間的相互影響、相互制約關係。

全局變量的泛濫必然預示著風險和災難。

(1)變量名衝突。

(2)耦合度難題。全局變量實際上大大增加了函數和模塊之間的耦合度。需要訪問某個特定全局變量的多個函數被該變量牢牢地“粘結”在一起,成為拆不散的一團亂麻。

(3)單個實例問題:全局變量不能阻止程序員定義一個類的多個對象實例。

(4)初始化順序:全局變量不可能保證相互之間遵循特定的初始化順序,這完全由編譯器決定。

(5)多線程訪問:

單件模式設計意圖

單件模式是創建型模式,保證一個類只有一個對象實例,並提供一個訪問該對象實例的全局訪問點。

將數據封裝在一個特殊的類中,這個類嚴格管理數據的創建過程以保證數據的唯一性,同時不允許程序員隨意創建該類的對象實例。

單件模式的基本結構


單件模式:隱式全局變量 vs. 顯式全局變量

單件類要負責創建這個類的唯一對象實例。

單件模式實現方式 類的靜態成員

面向對象設計和開發技術的主旨是對數據和相關操作的封裝。

在系統中提煉單件類的根本方法應該是,在面向對象分析與面向對象設計的基礎上,尋找那些具備單件類的特性、生命週期較長的類,把它們改寫成單件類的形式。

邊界類和控制類可以歸為單件類。

在C++語言中,類的所有實例共享一份靜態數據成員的拷貝,編譯器不會在每一個實例中分配靜態數據成員。這些靜態數據成員根本就不存在,除非按照定義全局變量的方式在類聲明代碼之外顯示地定義它們。C++語言為了語言的規範性,在語法上刻意區分了變量的聲明和定義這兩類不同的語句。

靜態數據成員是為了在一個類的所有實例中共用同一份數據拷貝而設計的,靜態數據成員必須由程序員自己負責定義,而靜態成員函數的作用則主要在於初始化和操作靜態數據成員,並且靜態成員函數只能操作靜態數據成員,而不能操作非靜態數據成員。

單件模式實現方式 單件類的忌諱

按照原來結構化程序設計的思路考慮問題,把全局變量作為模塊之間共享數據的一個橋樑,即把多個全局變量收集起來,放進一個單件類中,這完全是一種換湯不換藥、新瓶裝舊酒的做法,它雖然可以減少一些全局變量,部分地解決命名衝突問題,但是對系統的結構卻沒有任何好處,全局變量本身的風險依然存在。

面向對象設計和開發技術的主旨是對數據和相關操作的封裝。

如果在開發中為全局變量留下了生存的空間,那一定是由於系統設計還存在著不合理、不妥當的地方。

單件模式實現方式 單件類的來源

在系統中提煉單件類的根本方法應當是,在面向對象分析與面向對象設計的基礎上,尋找那些具備單件類的特性、生命週期較長的類,把它們改寫為單件類的形式。

邊界類和控制類的實例一般是單件類。

例子


單件模式:隱式全局變量 vs. 顯式全局變量


單件模式:隱式全局變量 vs. 顯式全局變量


單件模式:隱式全局變量 vs. 顯式全局變量


單件模式實現方式 單件類內存洩露

並不是所有沒有釋放的內存都對程序有害。

對於一個程序來說,如果某些內存的分配數據量有一個最大值,程序運行中所分配的內存總量不會超出該最大值,這些內存就可以被視為“內存池”,不釋放內存池的空間,並不會對整個系統造成傷害,因為它不會因無限增長而耗盡系統內存;如果在程序運行過程中,某些動態分配的內存空間會無限增長,就算客戶代碼非常小心,也無法避免內存耗盡(內存洩露)。

內存池並沒有太大的傷害,而內存洩露則必須嚴格規範。

在系統運行期間,單件類的對象實例有且只有一個,它佔據的內存數量是恆定的、不在增長的,即便不釋放該對象實例的內存空間,程序也不會受到任何威脅。

單件類的創建順序

協調不同單件類的創建順序,才能使整個系統正常運轉。

總結

1.變量名衝突:單件類可以減少全局變量的數量,部分地解決變量名衝突問題。相對而言,正確的面向對象分析和設計方法才是解決這一問題的關鍵;

2.耦合度難題:符合面向對象基本原則的單件類可以有效地降低系統的耦合度。

3.單個實例問題

4.初始化順序:合理地使用單件類可以確保不同對象的初始化順序,全局變量做不到這一點。

5.多線程訪問:在多線程環境下,單件類的對象實例和全局變量一樣都需要保護。


分享到:


相關文章: