C++知識點(6)_表驅動法替代if-else或switch語句

通常來說,出現不同數據格式轉換的場景,比如給定一個整數,將它與每週的星期名稱映射,通常會採用if-else或switch語句,但是這種語句存在兩個問題
(1)代碼太長,邏輯重複冗餘,複雜度高
(2)可維護性低,耦合性強,每新增一個流程分支,就要在函數代碼中新添加一個判斷語句。
這裏介紹一種通用的表驅動實現方法替代以上方式。
要實現一個通用的表驅動模式需要解決兩個問題:
(1)如何在表中註冊不同類型的執行函數?
(2)在表中找到對應的執行函數之後如何調用執行函數。由於每個函數的形參不盡相同,如何用統一的方式調用?
解決思路:
問題1:可以使用boost::Any解決
問題2:可以採用C++11的可變模板參數解決
通用的表驅動C++11實現支持各種類型的key,執行函數支持普通函數、函數對象、lamda表達式和成員函數。
.hpp文件

#ifndef TABLE_DRIVER_APPROACH_HPP_
#define TABLE_DRIVER_APPROACH_HPP_
#include<iostream>
#include<array>
#include<map>
#include<functional>
#include<type_traits>
#include<boost/any.hpp>
#include<typeinfo>
template<typename Key>
class TableDriver
{
public:
    template<typename... Args,typename Func>
    void Register(const Key& key,Func &&func)
    {
        typedef typename std::result_of<Func(Args...)>::type rettype;
        auto f=std::function<rettype(Args && ...)>([=](Args &&... args){return func(std::forward<Args>(args)...); });
        m_map[key]=f;
    }

    template<typename R=void,typename... Args>
    R Execute(const Key& key,Args &&... args) 
    {
        auto it=m_map.find(key);
        if(it==m_map.end())
        {
            return R();
        }
        auto f=boost::any_cast<std::function<R(Args && ...)> >(it->second);
        return f(std::forward<Args>(args)...);
    }

    template<typename R=void> //無參數
    R Execute(const Key& key)
    {
         auto it=m_map.find(key);
         if(it==m_map.end())
         {
             return R();
         }
         auto f=boost::any_cast<std::function<R()> >(it->second);
         return f();
    }
private:
    std::map<Key,boost::any> m_map;
};

#endif

測試代碼:

#include"TableDriveApproach.hpp"
TableDriver<int> dv;
const std::string GetDayName(const int& day)
{
    return dv.Execute<std::string>(day);
}
int main()
{
    dv.Register(0,[]()->std::string{return "星期日";});
    dv.Register(1,[]()->std::string{return "星期一";});
    dv.Register(2,[]()->std::string{return "星期二";});
    dv.Register(3,[]()->std::string{return "星期三";});
    dv.Register(4,[]()->std::string{return "星期四";});
    dv.Register(5,[]()->std::string{return "星期五";});
    dv.Register(6,[]()->std::string{return "星期六";});
    int day=3;
    std::cout<<GetDayName(day)<<std::endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章