重构 'execute and log' 模式
refactor 'execute and log' pattern
我发现自己一次又一次地遵循相同的模式:
if((return_code = doFoo1(...)) != CODE_OK) {
log("useful log message based on return code");
// very likely to return an error code.
}
// continue
if((return_code = doFoo2(...)) != CODE_OK) {
log("useful log message based on return code");
// very likely to return an error code.
}
知道如何避免这种恼人的模式并保持逻辑清晰吗?
有多种方法可以解决这个问题,这是一个基本的方法:
bool CheckAndLog( int code )
{
if( code == CODE_OK )
return true;
log( "<some error based on code>" );
return false;
}
if( !CheckAndLog( doFoo1(...) ) )
return;
如果您还需要 return 代码供以后使用,您可以 return 来自 CheckAndLog 的代码,或者将其作为传递引用参数,甚至将 CheckAndLog 变成 class 它存储最新的错误代码,您可以使用(可能有范围的)记录器实例实例化它来使用。
update 如果你想要文件和行信息,你需要 __FILE__
和 __LINE__
宏并避免在各处输入它们简单的宏就足够了:
bool CheckAndLog( int code, const char* file, unsigned line )
{
if( code == CODE_OK )
return true;
std::cerr << "file " << file << " line " << line
<< "<errormessage>" << std::endl;
return false;
}
#define CHECK( what ) (CheckAndLog( what, __FILE__, __LINE__ ))
更进一步,将调用的函数放入其中:因为它可以作为宏参数使用,所以它被预处理器扩展为这样。这意味着如果您键入 CHECK( foobar( 65 ) )
,则 what
参数在字面上被视为 foobar( 65 )
而不是 return 值。这是理想的,因为预处理器也可以 turn that into a string:
bool CheckAndLog( int code, const char* desc, const char* file, unsigned line )
{
if( code == CODE_OK )
return true;
std::cerr << desc << " from file " << file << " line " << line
<< "<errormessage>" << std::endl;
return false;
}
#define STRINGIZE1( x ) #x
#define STRINGIZE( x ) STRINGIZE1( x )
#define CHECK( what ) (CheckAndLog( what, STRINGIZE( what ), __FILE__, __LINE__ ))
我建议不要使用 CHECK
作为宏的名称,因为单元测试库也经常使用它。还要非常小心,不要将宏(无意或有意)重新定义为 #define CHECK( what ) (true)
之类的东西,因为这意味着如果你写
CHECK( foobar( 65 ) )
,函数永远不会被调用。
我发现自己一次又一次地遵循相同的模式:
if((return_code = doFoo1(...)) != CODE_OK) {
log("useful log message based on return code");
// very likely to return an error code.
}
// continue
if((return_code = doFoo2(...)) != CODE_OK) {
log("useful log message based on return code");
// very likely to return an error code.
}
知道如何避免这种恼人的模式并保持逻辑清晰吗?
有多种方法可以解决这个问题,这是一个基本的方法:
bool CheckAndLog( int code )
{
if( code == CODE_OK )
return true;
log( "<some error based on code>" );
return false;
}
if( !CheckAndLog( doFoo1(...) ) )
return;
如果您还需要 return 代码供以后使用,您可以 return 来自 CheckAndLog 的代码,或者将其作为传递引用参数,甚至将 CheckAndLog 变成 class 它存储最新的错误代码,您可以使用(可能有范围的)记录器实例实例化它来使用。
update 如果你想要文件和行信息,你需要 __FILE__
和 __LINE__
宏并避免在各处输入它们简单的宏就足够了:
bool CheckAndLog( int code, const char* file, unsigned line )
{
if( code == CODE_OK )
return true;
std::cerr << "file " << file << " line " << line
<< "<errormessage>" << std::endl;
return false;
}
#define CHECK( what ) (CheckAndLog( what, __FILE__, __LINE__ ))
更进一步,将调用的函数放入其中:因为它可以作为宏参数使用,所以它被预处理器扩展为这样。这意味着如果您键入 CHECK( foobar( 65 ) )
,则 what
参数在字面上被视为 foobar( 65 )
而不是 return 值。这是理想的,因为预处理器也可以 turn that into a string:
bool CheckAndLog( int code, const char* desc, const char* file, unsigned line )
{
if( code == CODE_OK )
return true;
std::cerr << desc << " from file " << file << " line " << line
<< "<errormessage>" << std::endl;
return false;
}
#define STRINGIZE1( x ) #x
#define STRINGIZE( x ) STRINGIZE1( x )
#define CHECK( what ) (CheckAndLog( what, STRINGIZE( what ), __FILE__, __LINE__ ))
我建议不要使用 CHECK
作为宏的名称,因为单元测试库也经常使用它。还要非常小心,不要将宏(无意或有意)重新定义为 #define CHECK( what ) (true)
之类的东西,因为这意味着如果你写
CHECK( foobar( 65 ) )
,函数永远不会被调用。