swa*_*log 3 c++ design-patterns readability
考虑一个应该提供参数建议的类,给出一些线索和特定的验收测试.
concretise的示例: 假设您根据文件名猜测原始数据文件的立方体尺寸.验收测试是:总元素==文件大小(假设1字节pr.网格单位).
这需要优先排序测试,其中每个测试进行一次或多次尝试通过验收测试.通过的第一个建议立即返回,不再尝试.如果没有通过,建议不要.
问题:当可读性是主要问题时,您会推荐哪种模式/方法?此外,以下建议有哪些缺陷和缺点?
方法1:获得成功验收测试的例外情况
我听说智者会在没有捕获实际异常的情况下避免使用try/catch.但是,在这种情况下,结果是相当可读的,看起来像:
try {
someTest1();
someTest2();
// ...
someTestN();
}
catch(int){
// Succesfull return
xOut = x_; yOut = y_; zOut = z_;
return;
}
xOut = -1; yOut = -1; zOut = -1;
Run Code Online (Sandbox Code Playgroud)
通过内部验收测试:
void acceptanceTest(const int x, const int y, const int z)
{
if (verify(x * y * z)) {
x_ = x; y_ = y; z_ = z;
throw 1;
}
}
Run Code Online (Sandbox Code Playgroud)
方法2:Do-while-false:
更改:所有测试在通过验收测试后立即返回true.如果测试中的所有尝试都失败,则返回false.
do {
if ( someTest1() ) break;
if ( someTest2() ) break;
// ...
if ( someTestN() ) break;
// All tests failed
xOut = -1; yOut = -1; zOut = -1;
return;
} while (0);
xOut = x_; yOut = y_; zOut = z_;
Run Code Online (Sandbox Code Playgroud)
验收测试:
bool acceptanceTest(const int x, const int y, const int z)
{
if (verify(x * y * z)) {
x_ = x; y_ = y; z_ = z;
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
方法3:函数指针数组
typedef bool (TheClassName::*Function)();
Function funcs[] = { &TheClassName::someTest1,
&TheClassName::someTest2,
// ...
&TheClassName::someTestN };
for (unsigned int i = 0; i < sizeof(funcs)/sizeof(funcs[0]); ++i) {
if ( (this->*funcs[i])() ) {
xOut = x_; yOut = y_; zOut = z_;
return;
}
}
xOut = -1; yOut = -1; zOut = -1;
Run Code Online (Sandbox Code Playgroud)
测试功能和验收测试与do-while-false相同.
方法4:转到
我已经看到do-while-false被称为伪装的goto,接着是如果这是预期的行为"为什么不使用goto?"的论点.所以我会列出来的:
if (someTest1() ) goto success;
if (someTest2() ) goto success;
// ...
if (someTestN() ) goto success;
xOut = -1; yOut = -1; zOut = -1;
return;
success:
xOut = x_; yOut = y_; zOut = z_;
return;
Run Code Online (Sandbox Code Playgroud)
测试功能和验收测试与do-while-false相同.
方法5:短路逻辑(Mike Seymour建议)
if (someTest1() ||
someTest2() ||
// ...
someTestN()) {
// success
xOut = x_; yOut = y_; zOut = z_;
return;
}
xOut = -1; yOut = -1; zOut = -1;
Run Code Online (Sandbox Code Playgroud)
测试功能和验收测试与do-while-false相同.
编辑:我应该指出,方法2,3,4,5与1的不同之处在于要求将验证测试的布尔返回值一直传递回返回函数,以及每个测试函数中增加的开销.多次尝试通过验收测试.
这使我认为方法1具有可维护性的优势,因为控制逻辑仅处于底层:验收测试.
方法5:短路逻辑
if (someTest1() ||
someTest2() ||
// ...
someTestN())
{
// success
}
Run Code Online (Sandbox Code Playgroud)
这相当于(并且在我看来更容易遵循)选项2和4,它们模拟其他流量控制操作的短路行为.
选项3非常相似,但更灵活; 如果你需要将相同的模式应用于不同的测试集,这可能是一个好主意,但如果你只有一组测试则是过度的.
选项1对很多人来说相当令人惊讶,因为例外通常只用于意外事件; 但是,如果测试的结构使得检测成功发生在深度调用链的某个地方,那么这可能比传递返回值更方便.它肯定需要记录,你应该抛出一个有意义名称的类型(例如success),并注意它不会被任何错误处理机制捕获.异常通常比正常函数返回慢得多,因此如果性能问题,请记住这一点.说了这么多,如果我想在这里使用异常,我当然会寻找简化测试结构的方法,以使返回值更方便.