首页 > 解决方案 > 是否有更好的实现来处理开关?

问题描述

我有一个名为回复的类类型,它的形式如下:

class reply {
public:
    enum class type {
        error = 0,
        bulk_string = 1,
        simple_string = 2,
        null = 3,
        integer = 4,
        array = 5
    };
public:
    type get_type(void) const {
        return type_;
    }
private:
    type type_;
};

回复实例将由其他函数返回,因此我将通过探测 get_type 调用的每个可能值来处理回复。第一个解决方案是使用 switch case,但我想使用“OOP”思想来封装它,如下所示:

template<typename Handlers, typename Handlers::type*...types>
class handlers {
private:
    static constexpr typename Handlers::type* dealers[] = { types... };
public:
    static void deal(const reply& reply) {
        dealers[int(reply.get_type())](reply);
    }
};

template<typename Handlers>
class handle{
public:
    using handles = handlers<Handlers, Handlers::error_handle,
        Handlers::bulk_string_handle, Handlers::simple_string_handle,
        Handlers::null_handle, Handlers::integer_handle,
        Handlers::array_handle>;
};
class handler
{
  
public:
    static void error_handle(const reply&) {
        std::cout << "error_handle" << std::endl;
    }
    static void bulk_string_handle(const reply&) {
        std::cout << "bulk_string_handle" << std::endl;
    }
    static void simple_string_handle(const reply&) {
        std::cout << "simple_string_handle" << std::endl;
    }
    static void null_handle(const reply&) {
        std::cout << "null_handle" << std::endl;
    }
    static void integer_handle(const reply&) {
        std::cout << "integer_handle" << std::endl;
    }
    static void array_handle(const reply&) {
        std::cout << "array_handle" << std::endl;
    }
public:
    using type = decltype(error_handle);
    using handles = handle<handler>::handles;
};

最后,我可以这样处理回复:

int main() 
{
   
    reply rep;
    handler::handles::deal(rep);
    return 0;
}

注意:每个回复都有其处理程序。我关注的是是否有更好的方法来适应解决方案?

标签: c++

解决方案


尽可能设计至少“中心点”。专注于使添加新回复类型变得容易,设计将基于该假设。使用选择处理程序的单个中心点创建与每个回复相关联的分离部分。中心点称为工厂,小部件实现相同的接口。

struct handler {
    // I do not know, maybe this should store the reply?
    // No idea.
    virtual void handle(const reply&);
    virtual ~handler();
};

struct error_handler : handler {
    void handle(const reply&) { /* blabla */ }
    handler construct() { return error_handler(); }
};
/* etc. for each handle type */

// TODO: convert to static array to save dynamic allocatiosn
std::map<std::reply::type, std::function<handler()>> handlers_map{
     { std::reply::error, []() { return error_handler(); } },
     /* etc. for each handle type */
};
handler handler_factor(const reply& r) {
      return handlers_map.at(r.get_type())();
}

#if YAY_AN_ARRAY // an example of converting map to a static array
// TODO: do it as a member function
static handler error_handler_construct() { return error_handler(); }
static std::array<handler (*)(), 1> handlers_array{
        &error_handler_construct,
        /* etc. */
};
handler handler_factor(const reply &r) {
        // remember about error handling
        return handlers_array.at(
           static_cast<int>(r.get_type())
        )();
}
#elif YAY_ANOTHER_ARRAY
static handler (*const handlers_array[])() = {
      [static_cast<int>(reply::type::error)] = &error_handler_construct,
      /* etc. */
};
handler handler_factor(const reply &r) {
       auto t = static_cast<int>(r.get_type();
       if (t < 0 || t > sizeof(handlers_array)/sizeof(*handlers_array)) {
            abort();
       }
       return handlers_array[t]();
}
#enidf

int main() {
   reply rep;
   auto h = handler_factor(rep);
   h.handle(rep);
   return 0;
}

推荐阅读