C/C++ 中一個簡單的 enum 手法(idiom)

  今天寫程序的時候,又用到這個 idiom 了,因而順便貼出來。這個 idiom 蠻簡單的,估計不少人都用過。今天主要是貼出來給新手參考(老手們就甭費時看此帖了)。
  爲了說明這個手法具體該咋用,咱舉一個簡單的例子來講事兒。比方說要開發一個網絡程序,其中須要統計各類網絡協議的數據包數量。
 程序員

★版本1


  假設一開始只須要處理 HTTP 和 FTP 兩種協議。有些同窗不假思索,當即會聲明以下兩個整數用於統計:數組

int nCntHttp = 0;
int nCntFtp = 0;


  猛一看,彷佛沒啥問題。可是,若是需求發生變動,又要增長兩種協議:SMTP 和 SSH。而後,該同窗會繼續擴展上述代碼,變爲以下:網絡

int nCntHttp = 0;
int nCntFtp = 0;
int nCntSmtp = 0;
int nCntSsh = 0;


  這時候,問題開始顯露出來了。比方說要打印上述4統計值,就得寫4個 printf 語句;再假如要用斷言確保全部統計值大於零,也得寫4個 assert 斷言。這都是挺煩人的事兒。(固然啦,有些同窗會把4個變量的打印寫在一個 printf 中,但仍是同樣煩人)
 spa

★版本2


  這可咋辦捏?有點小聰明的程序猿就靈機一動,把上述代碼修改成數組形式,上述的4個統計值【依次】放入數組中。具體以下:ip

int nCntProto[4];
/* 第0個是HTTP,第1個是FTP,第2個是SMTP,第3個是SSH */


  這樣一來,不管是打印仍是斷言,用一個 for 循環就搞定,貌似挺方便滴。
  但這麼一來,引入了另外一個問題:假設我在程序中要用到 SMTP 的統計數字,就得這麼寫代碼:開發

nCntProto[2]


  這就形成了很不雅觀的「Magic Number」!要知道,Magic Number 但是代碼的臭味之一啊(其弊端在「這篇博文」中曾經介紹過)。萬一未來,數組中的存放順序發生變化,那就完蛋了:好多用到 Magic Number 的代碼都得跟着改。一旦漏改某處,引出 Bug 無數!
 get

★版本3


  爲了消除 Magic Number,增長代碼可讀性和可維護性,有些同窗開始打起 enum 的主意。在代碼中增長了一組 enum,具體以下:it

enum PROTO
{
    PROTO_HTTP,
    PROTO_FTP,
    PROTO_SMTP,
    PROTO_SSH,
};

int nCntProto[4];


  這樣,若是我須要用到 SMTP 的統計數字,我就不用寫io

nCntProto[2]

而是寫容器

nCntProto[PROTO_SMTP]

  顯然,可讀性明顯好多了。即便未來數組中的存放順序發生變化,也不要緊:只需稍微調整 enum 中常量的順序便可,其它代碼不用動。
 

★版本4


  可是,仍是有一個不爽的地方。定義數組的語句用到了「4」這個 Magic Number。萬一未來需求繼續變動,繼續增長協議,那這個數字還得不斷調整。仍是有點不爽!
  咋辦捏?這時候,終極版本隆重登場。請看以下代碼:

enum PROTO
{
    PROTO_HTTP,
    PROTO_FTP,
    PROTO_SMTP,
    PROTO_SSH,

    PROTO_NUM  /* 表示協議數量 */
};

int nCntProto[PROTO_NUM];


  這種寫法的好處在於,【沒有任何一個】Magic Number 出如今代碼中。無論是引用某個統計值仍是循環遍歷數組,都使用的是定義好的常量。
  就算將來發生需求變動,要增長新的協議,只要往 enum 中增長相應的 enum 常量便可(但要記得保證 PROTO_NUM 位於 enum 定義的末尾)。因爲 PROTO_NUM 會自動跟着增加,因此其它的代碼幾乎不會受到影響。
 

★C++ 的補充說明


  上述代碼同時適用於 C 和 C++。不過捏,某些 C++ 程序員或許看不慣原始數組,以爲 STL 的容器類看起來比較順眼。那也沒啥大關係:只要把上述代碼中聲明數組的那句修改成以下,其它的代碼基本照舊。

std::vector<int> vctCntProto(PROTO_NUM);
相關文章
相關標籤/搜索