之前我们讲过某些时候可以利用数组来代替if/else来优化代码, 在本文中, 我们再次来复习一下, 顺便学学利用配置文件来优化代码结构, 好, 开始吧。
假设有这样一个场景: 某系统会产生三类错误, 分别是:ERROR_TYPE_ONE, ERROR_TYPE_TWO, ERROR_TYPE_THREE. 但是呢, 各省份有不同的需求, 比如:
1. 安徽省要求遇到上述三种错误后分别显示:101, 102, 103
2. 湖北省要求遇到上述三种错误后分别显示:1001, 1002, 1003
3.广东省要求遇到上述三种错误后分别显示:10001, 10002, 10003
4.黑龙江要求遇到上述三种错误后分别显示:201, 202, 203
5.浙江省要求遇到上述三种错误后分别显示:2001, 2002, 2003
面对这些省份的不同要求, 我们该怎么搞呢? “最勤奋”的程序猿写出来的代码是:
#include <iostream>
using namespace std;
enum ErrorType
{
UNDEFINED,
ERROR_TYPE_ONE,
ERROR_TYPE_TWO,
ERROR_TYPE_THREE,
};
int main()
{
char szProvince[100] = {0};
cin >> szProvince;
int error = -1;
cin >> error;
if(0 == strcmp("anhui", szProvince))
{
if(ERROR_TYPE_ONE == error)
{
cout << 101 << endl;
}
else if(ERROR_TYPE_TWO == error)
{
cout << 102 << endl;
}
else if(ERROR_TYPE_THREE == error)
{
cout << 103 << endl;
}
}
if(0 == strcmp("hubei", szProvince))
{
if(ERROR_TYPE_ONE == error)
{
cout << 1001 << endl;
}
else if(ERROR_TYPE_TWO == error)
{
cout << 1002 << endl;
}
else if(ERROR_TYPE_THREE == error)
{
cout << 1003 << endl;
}
}
if(0 == strcmp("guangdong", szProvince))
{
if(ERROR_TYPE_ONE == error)
{
cout << 10001 << endl;
}
else if(ERROR_TYPE_TWO == error)
{
cout << 10002 << endl;
}
else if(ERROR_TYPE_THREE == error)
{
cout << 10003 << endl;
}
}
if(0 == strcmp("heilongjiang", szProvince))
{
if(ERROR_TYPE_ONE == error)
{
cout << 201 << endl;
}
else if(ERROR_TYPE_TWO == error)
{
cout << 202 << endl;
}
else if(ERROR_TYPE_THREE == error)
{
cout << 203 << endl;
}
}
if(0 == strcmp("zhejiang", szProvince))
{
if(ERROR_TYPE_ONE == error)
{
cout << 2001 << endl;
}
else if(ERROR_TYPE_TWO == error)
{
cout << 2002 << endl;
}
else if(ERROR_TYPE_THREE == error)
{
cout << 2003 << endl;
}
}
return 0;
}
我们看看上面的代码结果, 一看就感觉是重复啰嗦加累赘, 可能有的初学者说, 这很自然啊, 如果优化的话, 可以用switch来优化啊. 其实, 用switch又怎样呢? 还不是一样的垃圾代码?
我们之前说过用数组优化if/else, 我们可以考虑一下数组。 但此处我自问一下, 为什么数组可以优化? 因为数组的本质就是映射! 废话少说, 直接上代码:
#include <iostream>
using namespace std;
int a[][3] =
{
{101, 102, 103},
{1001, 1002, 1003},
{10001, 10002, 10003},
{201, 202, 203},
{2001, 2002, 2003}
};
int main()
{
char szProvince[100] = {0};
cin >> szProvince;
int error = -1;
cin >> error;
if(error < 1 || error > 3)
{
return 1;
}
if(0 == strcmp("anhui", szProvince))
{
cout << a[0][error - 1] << endl;
}
if(0 == strcmp("hubei", szProvince))
{
cout << a[1][error - 1] << endl;
}
if(0 == strcmp("guangdong", szProvince))
{
cout << a[2][error - 1] << endl;
}
if(0 == strcmp("heilongjiang", szProvince))
{
cout << a[3][error - 1] << endl;
}
if(0 == strcmp("zhejiang", szProvince))
{
cout << a[4][error - 1] << endl;
}
return 0;
}
看看, 是不是简洁多了。 其实上述代码还可以优化, 我们只需要建立字符串到整数的映射即可, 如下:
#pragma warning(disable : 4786)
#include <iostream>
#include <string>
#include <map>
using namespace std;
int a[][3] =
{
{101, 102, 103},
{1001, 1002, 1003},
{10001, 10002, 10003},
{201, 202, 203},
{2001, 2002, 2003}
};
typedef map<string, int> strMapInt;
typedef map<string, int> :: iterator It;
strMapInt g_map;
void buildMap()
{
g_map.insert(make_pair(string("anhui"), 1));
g_map.insert(make_pair(string("hubei"), 2));
g_map.insert(make_pair(string("guangdong"), 3));
g_map.insert(make_pair(string("heilongjiang"), 4));
g_map.insert(make_pair(string("zhejiang"), 5));
}
int main()
{
buildMap();
char szProvince[100] = {0};
cin >> szProvince;
int error = -1;
cin >> error;
if(error < 1 || error > 3)
{
return 1;
}
It it = g_map.find(string(szProvince));
if(g_map.end() != it)
{
cout << a[it->second - 1][error - 1] << endl;
return 0;
}
return 1;
}
但是呢, 上述程序有两个问题: 1. 如果某个省份比较讨厌, 它突然要改变对应的错误码显示, 比如安徽想把101变为1000001. 这个时候, 程序猿不得不动代码了。 2. 如果要增加一些省份怎么办呢? 这个时候, 程序猿也需要动代码了。
下面, 我们考虑利用配置文件来进行优化, 通常来讲, 在这种情况下, .xml文件做配置文件是非常适合的, 但为了简便起见, 我们用.txt文件来代替。 我们在config.txt文件中制作如下内容(以安徽为例):
1
101
2
102
3
103
然后改程序如下:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
int error = -1;
cin >> error;
ifstream infile("config.txt");
string line;
int n = 0;
if(infile)
{
while(getline(infile, line))
{
if(atoi(line.c_str()) == error)
{
getline(infile, line); // 取下一行
n = atoi(line.c_str());
cout << n << endl;
return 0;
}
}
}
return 1;
}
我们可以看到, 这个程序不怕省份增多, 也不怕省份的错误码变更。 我们需要做的是, 对每一个省份, 搞个配置文件即可。
不得不说, 说面的程序还是很fragile的。需要在程序中增加更多异常的判断, 比如检验配置文件格式的合法性。 但是, 在本文中, 我们仅作示例, 所以有很多异常情况并没有考虑。
总结一下:配置文件的引入, 使得程序对于需求变化不敏感, 也就是说, 程序不怕需求变化, 体现了很好的可扩展性, 回味一下, 确实如此。 实际的软件开发中, 有很多类似这样的地方, 建议大家注意程序结构的合理性。