Chinaunix首页 | 论坛 | 博客
  • 博客访问: 846045
  • 博文数量: 756
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 4980
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:40
文章分类

全部博文(756)

文章存档

2011年(1)

2008年(755)

我的朋友

分类:

2008-10-13 16:14:31

不针对任何人的说:
        看到有人把Error Msg写死到代码里,我就有上去忽他一巴掌的冲动。比如如下代码:

int funcFoo()
{
    UpdateData();

    int error_code = 0;

    if (!IsInPutsUseName()) error_code = -1;
    else if(!IsInputAllPsw()) error_code = -2;
    else if(!IsTwoPswTheSame()) error_code = -3;
    else if(!IsThePswMachWithDatabase()) error_code = -4;

    if (error_code != 0)
    {
        switch(error_code)
        {
            case -1 : MessageBox("请输入用户名,然后重试!", "未输入用户名", MB_OK | MB_ICONWARNING); break;
case -2 : MessageBox("请输入所有的密码,然后重试!", "未输入密码", MB_OK | MB_ICONWARNING); break; case -3 : MessageBox("您输入的两次密码不一致,请重新输入!", "密码不一致", MB_OK | MB_ICONWARNING); break; case -4 : MessageBox("您输入的密码错误,请重新输入", "密码错误", MB_OK | MB_ICONWARNING); break; case default : break; } DeleteInputPsw(); return error_code; } UpdateData(false);
return
error_code;
}

   理由如下:
1. 这样的源码不易阅读。假设用户提供的一个错误信息,我要追踪其源码,我去那里找呀?可能有很多处地方都会有重复的类似的MSG出现,比如"请输入用户名,然后重试!"和"请您输入用户名,然后重试!"就会被认为是2条不同的MSG。这样很难排错。
2. 用户那里有可能弹出你估计之外的错误。实际上我们经常遇到这种情况,某程序崩溃探出一个错误号,没信息。因为没有对应好。
3. 不利于发展为多语言版本?(你指望专业翻译在你的代码里搜索字符串?)
4.不利于全局统计。估计自己都不知道自己的工程里已经存在了多少种MSG字符串了吧?
5.专业软件的错误信息是应该由专业语言措辞人员去对应的,而不是由程序员决定最终的版本。比如我代码里写一个errorcode:992,“没输密码!”,就会被专业措辞人员修饰为"请输入用户名,然后重试!"

    解决的方法

也有多种,各有其优点和不足之处,写在这里供大家参考:
1.最古老的做法,是把信息写入一个文本文件里面:
     // xxxxxxxxxx  一些注释 xxxxxxxxxxx
     // xxxxxxxxxx  一些注释 xxxxxxxxxxx
     // xxxxx Error Code : 998
     // xxxxx Msg :   "请输入用户名,然后重试!"
     // xxxxx 描述: ...
     #define Error_998_MSG  "请输入用户名,然后重试!"  
     
     // xxxxxxxxxx  一些注释 xxxxxxxxxxx
     // xxxxxxxxxx  一些注释 xxxxxxxxxxx
     // xxxxx Error Code : 999
     // xxxxx Msg :   "xxxxxxxxx, xxxxxxxxxxxxxxx!"
     // xxxxx 描述: ...
     #define Error_999_MSG  "xxxxxxxxxxxxxxxx!" 
     诸如此类的做法,当系统启动的时候把这些资源读入内存中
    优点:已经基本上解决了上述所说的弊病;
    缺点:跨平台交互不容易,尤其是文件内码不同的情况,比如utf-8环境、ansi char环境、unicode环境...........

2.  写入xml文件里面:(推荐)
    这种做法和上述方法类似,不过解决了上述方法的缺点。常用于Web相关的开发。
   优点:标记语言,交互方便。扩展方便,功能强大且无限制。
   缺点:编写人员必须熟悉xml语法,或者有专用的用于简化生成这个xml文件的程序。

3. 写入数据库里面:
     应用这种方法的也很多,我就遇到若干这种做法的项目。形象一点的说,你可以参考Sql Server中的错误信息,它也是写在一个系统表里面。
     优点:利用SQL的优势,编写、修改都很方便,程序员、翻译、维护人员和用户都很轻松。客户甚至可以自己修改MSG信息。
     缺点:一般这种做法只用于数据库相关的应用,比如MIS系统。另外,如果出现数据库根本连接不上的错误,这种错误信息还要当作特例解决。
     另外,交互-速度较慢。
   
今天在论坛上偶见此问题,遂废话一堆,抛砖引玉,希望大家批评指正。

-------------
乾坤一笑 写于2005年1月19日  转载请标明出处和原文链接


--------------------next---------------------
1、用宏替代,把这些东西写成宏放到一个头文件中:
#define MSG_ERROR_NO_USER_NAME "未输入用户名"
#define MSG_ERROR_NO_INPUT_ALL_PASSWORD "..."
2、把这些东西放到资源文件中,不用再说了吧
3、定义一个类:
class GetErrorMsg
{
const std::string get_no_user_name()
{
return std::string("");
}
const std::string get_no_input_all_password()
{
return std::string("");
}
!!!
void SerializeFromFile(const char *filename)
{
..从文件中读入
}
void SerializeFromResourceDll(const char *countryID)
{
..从一个资源中读入
}
}
4、我们现在不直接返回了,我们抛异常
class NoUserNameException : public std::exception
{
.....
std::string msg="";
}
class NoInputAllPasswordException : public std::exception
{
..
std::string msg="";
}
到时候直接抛各种异常出来,让最高层去处理
5、我们只抛一个异常
enum ERRORTYPE
{
NO_USER_NAME,
NO_INPUT_ALL_PASSWORD,
...
}
class InputErrorException : public std::exception
{
public:
InputErrorException(ERRORTYPE errorType)
{
...
}
}
6、我们返回一个错误值,
return -12;
然后我们在另外一个处理错误值的里面
char *get_error_msg(int errorID)
{
char *errors[]=
{
"未...","sdf",...
};
}
--------------------next---------------------
class GetErrorMsg
{
const std::string get_no_user_name()
{
return std::string("");
}
const std::string get_no_input_all_password()
{
return std::string("");
}
!!!
void SerializeFromFile(const char *filename)
{
..从文件中读入
}
void SerializeFromResourceDll(const char *countryID)
{
..从一个资源中读入
}
void SerializeFromDataBase(IDateBase *db)
{
..从数据库读入
}
void SerializeFromXmlFile(const char *xmlfilename0
{
..从xmlfile读入
}
}
假如倾向于喜欢类库设计的话,可以另外抽象一接口
class IConfig
{
void get_no_inputMsg();
void get_no_all_passwordMsg();
virtual void Load();
virtual void Unload();
}
class XmlConfig : public IConfig
{
virtual void Load();
virtual void Unload();
}
class DbConfig : public IConfig
{
virtual void Load();
virtual void Unload();
}
class TextFileConfig : public IConfig
{
virtual void Load();
virtual void Unload();
};
另外还可以有RegistryConfig,....
目的很简单就是将字符串的获得这一接口抽象出来,
--------------------next---------------------

阅读(1238) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~