在基于I / O的对象上执行一系列操作的设计模式

时间:2016-05-26 17:55:14

标签: c++ design-patterns

我发现自己经常编写遵循以下顺序的代码:

  1. 尝试打开基于I / O的资源(即来自数据库和/或文件)。这可能会失败。
  2. 如果成功,请通过对象执行一系列操作。
    • 这些操作根据用户输入而变化。例如:过滤数据,做计算A,做计算B,在某处写结果。
    • 这些操作中的每一个都可能失败并返回错误消息。如果任何时候发生故障,则序列应该中止。
    • 某些操作必须先于其他操作:例如,在计算之前不能写入结果。
  3. 关闭资源。
  4. 是否有适用于此类流程的设计模式?当我尝试将上面的序列包装成一个类时,我经常遇到的直接问题是:

    • 如何处理打开资源。理想情况下,我想在课程构建期间打开它,但如果出现错误则会变得混乱。否则,我必须在构造函数中传入对资源的引用,然后是Open()方法。
    • 如何使操作流程对对象的用户灵活,但不需要记住调用一堆中间方法和/或大量错误检查。

1 个答案:

答案 0 :(得分:1)

拒绝允许异常处理的组织通常不会处理一组虚假处所。

话虽如此,如果可以证明没有异常可以从有问题的代码块中逃脱,也许可以说服您的组织允许有限的异常使用:

Parse.initialize(new Parse.Configuration.Builder(this)
        .applicationId(Const.APP_ID)
        .server(Const.SERVER_URL)
        .clientKey("")
        .build());

预期产出:

#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;
}