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);
相关文章
相关标签/搜索