我发现自己经常按照以下顺序编写代码:
- 尝试打开基于 I/O 的资源(即来自数据库和/或文件)。这可能会失败。
- 如果成功,通过对象执行一系列操作。
- 这些操作会根据用户输入而变化。比如:过滤数据,做A计算,做B计算,把结果写到某处。
- 这些操作中的每一个都可能失败并返回一条错误消息。如果在任何时候发生故障,序列应该中止。
- 有些操作必须先于其他操作完成:例如,写入结果不能发生在计算之前。
- 关闭资源。
有没有适合这种流程的设计模式?当我尝试将上述序列包装到一个类中时,我经常遇到的直接问题是:
- 如何处理打开资源。理想情况下,我想在类构造期间打开它,但如果出现错误,那会变得困惑。否则,我必须在构造函数中传递对资源的引用,然后是
Open()
方法。 - 如何使操作流程对对象的用户而言灵活,但又不会因为需要记住调用一堆中间方法和/或大量错误检查而给他们带来负担。
最佳答案
拒绝允许异常处理的组织往往是在一组错误的前提下工作。
话虽这么说,如果可以证明没有异常可以从相关代码块中逃脱,也许可以说服您的组织允许有限地使用异常:
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
struct exception_swallower
{
void set_error(std::string msg)
{
success = false;
message = std::move(msg);
}
bool success = true;
std::string message;
};
std::ostream& operator <<(std::ostream& os, const exception_swallower& es)
{
if (es.success) {
return os << "success";
}
else {
return os << "failure: " << es.message;
}
}
// @pre stream shall be initialised with an r-value reference
// to a stream which has already had 'open' called on it.
//
template<class Stream, class Op>
exception_swallower perform_op_on_stream(Stream stream, Op op)
{
// our non-exception return type
exception_swallower ret;
// catch all exceptions
try {
// check that stream did open
if (!stream) {
throw std::runtime_error("stream didn't open");
}
// perform the operations
op(stream);
}
catch(const std::exception& e)
{
// reflect failures in the returned object
ret.set_error(e.what());
}
return ret;
}
// some sample operations
auto null_op = [](auto& ios)
{
// do nothing
};
auto error_op = [](auto& ios)
{
// throw an exception
throw std::runtime_error("error in stream");
};
int main(int argc, char** argv)
{
// note: the stream is created as a temporary, which
// automatically yields an r-value reference.
std::cout << perform_op_on_stream(std::ifstream(argv[0]), null_op) << std::endl;
std::cout << perform_op_on_stream(std::ifstream(argv[0]), error_op) << std::endl;
}
预期输出:
success
failure: error in stream
关于c++ - 对基于 I/O 的对象执行一系列操作的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37467931/