[英]How do I avoid both global variables and magic numbers?
我知道並了解,全局變量和幻數是編程時要避免的事情,尤其是隨着項目中代碼量的增長。 但是,我想不出一個很好的方法來避免兩者。
假設我有一個代表屏幕寬度的預定變量,並且在多個文件中需要該值。 我可以做...
doSomethingWithValue(1920);
但這是一個神奇的數字。 但是要避免這種情況,我會...
const int SCREEN_WIDTH = 1920;
//In a later file...
extern const int SCREEN_WIDTH;
doSomethingWithValue(SCREEN_WIDTH);
現在我正在使用全局變量。 這里有什么解決方案?
在第二個示例中, SCREEN_WIDTH
實際上不是變量 1 ,而是一個命名常量 。 使用命名常量完全沒有錯。
在C語言中,如果它是一個整數常量,則可能要使用一個枚舉,因為const對象不是常量。 在C ++中,最好像在原始問題中一樣使用const對象,因為在C ++中,const對象是常量。
1.從技術上講,是的,它是一個“變量”,但是該名稱並不是真正的“正確”,因為它永遠不會更改。
我建議在頭文件的名稱空間中定義常量。 然后,該范圍就不是全局的,並且您無需在多個地方重新定義它(即使使用extern關鍵字)。
為什么首先需要對屏幕寬度進行硬編碼? 它從何而來? 在大多數實際應用程序中,它來自某些系統API,該API告訴您當前正在運行的分辨率或系統能夠顯示的分辨率。
然后,您只需獲取該值,然后將其傳遞到所需的任何地方即可。
簡而言之,在這一行: doSomethingWithValue(SCREEN_WIDTH);
你已經在做了。 在此特定示例中, SCREEN_WIDTH
可能是全局SCREEN_WIDTH
,但不一定是全局變量,因為該函數未將其作為全局變量進行訪問 。 您將在運行時將值傳遞給函數,因此函數看到的不是全局變量,而只是一個簡單的函數參數。
另一個重要的一點是, 不變的全局數據通常沒有錯。
全局常數通常很好。 當你有可變的全局狀態出現該問題:對象可以在所有應用程序的訪問,並根據當你看到上可能有不同的價值。 這使得難以推理,並導致許多問題。
但是全局常量是安全的。 以pi為例。 這是一個數學常數,而且也讓中每個函數看到pi為3.1415任何傷害.....因為這是它是什么,它不會改變。
如果屏幕寬度是一個硬編碼的常量(如您的示例中所示),那么它也可以是全局的而不會造成破壞。 (盡管出於明顯的原因,它最初可能不應該是一個常數9
全局變量的主要問題是它們是非常量的。 不變的全局變量幾乎不是問題,因為您始終知道它們的使用價值。
在這種情況下,一種理智的方法是創建一個常量名稱空間,並將常量值放在此處,以在程序中的任何位置進行引用。 這很像您的第二個示例。
它們必須在某處定義。 為什么不將定義放在.h文件或構建文件中?
它不是變量,而是常量,可以在編譯時解析。
無論如何,如果您不喜歡這樣的“浮動”常量,則可以將其放在名稱空間中,或者將其收集在一起的所有類型。 在某些情況下,您還可以考慮使用枚舉對相關常數進行分組。
更好的是,如果這適合您的情況,請避免使用固定的預定屏幕寬度,並使用正確的API在運行時檢索它。
如果必須要有一個全局變量,那么通常將其包裝在一個函數中並使用該函數來獲取值通常是一個好主意。
另一則可能有幫助的帖子
雖然在第二種情況下,全局是一個無害的全局,但是除非您為確定屏幕寬度不會改變的東西設計該全局,否則我將使用某些東西來動態獲取屏幕寬度(例如, GetSystemMetrics
on Windows,或X上的XDisplayWidth
)。
避免這種情況的一種方法是將程序設置為對象,並在該對象上具有屬性(my_prog.screen_width)。 要運行程序,請讓main()實例化該對象並在該對象上調用-> go方法。
Java執行此操作。 很多。 半體面的想法。
程序擴展的附加功能:
但是,對於快速的一次性計划而言,這並不是什么大問題。
重要的是要認識到,即使將來需要更改全局常量,有時也會引起問題。 在某些情況下,您可能會決定不讓它們進行更改,但是有時情況可能並不那么容易。 例如,您的程序可能包含大小與屏幕大小匹配的圖形圖像。 如果需要對其進行調整以在不同尺寸的屏幕上運行該怎么辦? 僅更改命名常量不一定會修復程序中嵌入的圖形圖像。 如果需要在運行時決定使用什么尺寸的屏幕該怎么辦?
不可能應對所有可能的意外情況,並且不應過分努力以防止那些根本不會發生的事情。 但是,應該注意事情會發生什么變化,以免陷入困境。
當設計一個類時,具有一個虛擬的只讀屬性並返回一個不變的值將允許該類的將來的擴展返回不同的值。 使用屬性而不是常量可能會影響性能,但是在某些情況下,靈活性是值得的。 如果有一種方法可以定義虛擬常量,那可能會很好,而且我認為沒有理由在理論上不允許.net允許它(包括帶有虛擬方法指針的表中的常量值),但到目前為止我知道不是。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.