zoukankan      html  css  js  c++  java
  • (原创)c++11改进我们的模式之改进表驱动模式

    所谓表驱动法(Table-Driven Approach),简单讲是指用查表的方法获取值。表驱动是将一些通过较为复杂逻辑语句来得到数据信息的方式,通过查询表的方式来实现,将数据信息存放在表里。对于消除长的switch-case和if-else-if语句来说很有效,比如下面的代码:

    string GetDayName(int day)
    {
    string dayName;
    if(day==1)
      {
       dayName="星期一";
     }
     else if(day==2)
      {
       dayName="星期二";
     }
     else if(day==3)
      {
       dayName="星期三";
     }
    else if(day==4)
      {
       dayName="星期四";
     }
    else if(day==5)
      {
       dayName="星期五";
     }
     else if(day==0)
      {
       dayName="星期日";
     }
    }

    这样的主要问题是:

    • 代码太长,逻辑重复,圈复杂度高;
    • 可维护性低,当新增一个流程分支时就要添加一个判断语句。

    通过表驱动就一两条语句就可以代替上面长长的if-else语句。

    string GetDayName(int day)
    {
    string dayNames[] = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
    return dayNames[day]
    }

    这样不仅代码看起来简明,而且后面如果增加新的数值的话维护起来也更简单、方便。

    表驱动法虽然对于消除长的if-else语句、提高代码质量很有用,但是一般的表驱动难以重用,即这个类的表驱动难以被其它类的表驱动所重用,因为其它类的表驱动逻辑和当前类的逻辑并不一定相同,具体来说是逻辑分支的函数不尽相同,这个问题导致表驱动模式的实现不够通用。

    如果要做一个通用的表驱动模式就会面临两个问题,第一个问题是如何在表中注册各种类型的执行函数,这些执行函数形参不尽相同,用function是不行的,因为function的类型在一开始就定下来了;第二个问题是表找到了相应的执行函数之后调用该函数的问题,因为每个函数的形参不尽相同,如何以一种统一的方式去调用也是一个问题;问题二比较好解决,用c++11的可变模板参数即可;问题一需要通过类型擦除来解决,这要用到前面2.3.5节中实现的any做这个事情。c++11版本的表驱动模式,支持各种类型的key,执行函数支持普通函数、函数对象、lamda表达式和成员函数。

    c++11之前写一个通用表驱动模式面临两个问题,第一个问题是如何在表中注册各种类型的执行函数,这些执行函数形参不尽相同,用function是不行的,因为function的类型在一开始就定下来了;第二个问题是表找到了相应的执行函数之后调用该函数的问题,因为每个函数的形参不尽相同,如何以一种统一的方式去调用也是一个问题;问题二比较好解决,用c++11的可变模板参数即可;问题一需要通过类型擦除来解决,这要用到boost::any做这个事情。c++11版本的表驱动模式,支持各种类型的key,执行函数支持普通函数、函数对象、lamda表达式和成员函数。

    上代码:

    #include <functional>
    #include <type_traits>
    template<typenameKey>
    class TableDriver
    {
    public:
        template<typename... Args, typenameFunc>
        void Register(Key&&key, Func&&func)
        {
            //typedef decltype(std::declval<Func>()(std::declval<Args>()...)) rettype;
            typedeftypename std::result_of<Func(Args...)>::typerettype;
            auto f = std::function<rettype(Args&& ...)>([=](Args&& ... args){return func(std::forward<Args>(args)...); });
            m_map[key] = f;
        }
    
        template<typenameR = void, typename... Args>
        R Execute(Key&&key, Args&&... args)
        {
            auto it = m_map.find(key);
            if (it == m_map.end())
                return (R)nullptr;
    
            auto f = it->second.AnyCast<std::function<R(Args&& ...)>>();
            return f(std::forward<Args>(args)...);
        }
    
        //不带参数的执行
        template<typenameR>
        R Execute(Key&&key)
        {
            auto it = m_map.find(key);
            if (it == m_map.end())
                return (R)nullptr;
    
            auto f = it->second.AnyCast<std::function<void()>>();
            return f();
        }
    
    private:
        std::map<Key, Any> m_map;
    };

    测试代码:

    struct MyStruct2
    {
    	void g(int x)
    	{
    		cout<<x<<endl;
    	}
    
    	void g1()
    	{
    		cout<<2<<endl;
    	}
    };
    
    struct MyStruct3
    {
    	void operator()(int x) const
    	{
    		cout<< x +1<<endl;
    	}
    };
    
    void TestTbDriver()
    {
    	TableDriver<int> dv;
    	auto f = [](int a, int b){cout<<a+b<<endl;}; 
    	auto fuc = [](int a){cout<<a<<endl;};
    	auto fuc1 = [](){cout<<1<<endl;};
    
    	dv.Register<decltype(f),int,int>(1, f); //带参数的lamda表达式
    	dv.Register<decltype(fuc), int>(2, fuc);
    	dv.SimpleRegister<decltype(fuc1)>(22, fuc1); //不带参数的lamda表达式
    	
    	MyStruct2 st2;
    	dv.Register<int>(4, &st2, &MyStruct2::g); //带参数的成员函数
    	MyStruct3 st3;
    	dv.Register<decltype(st3), int>(11, st3); //函数对象
    	dv.SimpleRegister(44, &st2, &MyStruct2::g1); //不带参数的成员函数
    
    	int a=3,b=4;
    	dv.Execute(2, a);
    	dv.Execute(1, a, b);
    	dv.Execute(22);
    	dv.Execute(44);
    	dv.Execute(11, a);
    }
    
    structTdd
    {
        int Test(intx)
        {
            returnx + 2;
        }
    };
    
    void TestDriver()
    {
        TableDriver<string> dv;
        dv.Register("aa", []{cout <<"aa test;"<< endl; });
        dv.Execute("aa");
    
        int y = 0;
        dv.Register<int, int>("aa", [](inta, intb){returna + b; });
        auto t = dv.Execute<decltype(y)>("aa", 3, 4);
    
        Tdd a;
        dv.Register<int>("aa", [&a](intx){return a.Test(x); });
        auto t1 = dv.Execute<int>("aa", 3);
    
        dv.Register<string>("aa", [](stringx){returnx; });
        auto t2 = dv.Execute<string>(std::move(string("aa")), std::move(string("test")));
    }

    测试结果:

    /**********************做一个更新,对代码进行简化和优化,更少的代码,并且可以带返回值了 **********************/

    代码中用到的Any就是博客:http://www.cnblogs.com/qicosmos/p/3420095.html 中的Any

    #include "Any.hpp"

    template<typename Key>
    class TableDriver
    {
    public:
    template<typename... Args, typename Func>
    void Register(Key && key, Func&& func)
    {
    //typedef decltype(std::declval<Func>()(std::declval<Args>()...)) rettype;
    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(Key && key, Args&&... args)
    {
    auto it = m_map.find(key);
    if (it == m_map.end())
    return (R)nullptr;

    auto f = it->second.AnyCast<std::function<R(Args && ...)>>();
    return f(std::forward<Args>(args)...);
    }

    //不带参数的执行
    template <typename R>
    R Execute(Key && key)
    {
    auto it = m_map.find(key);
    if (it == m_map.end())
    return (R)nullptr;

    auto f = it->second.AnyCast<std::function<void()>>();
    return f();
    }

    private:
    std::map<Key, Any> m_map;
    };

    测试代码:

    struct Tdd
    {
    int Test(int x)
    {
    return x + 2;
    }
    };

    void TestDriver()
    {
    TableDriver<string> dv;
    dv.Register("aa", []{cout << "aa test;" << endl; });
    dv.Execute("aa");

    int y = 0;
    dv.Register<int, int>("aa", [](int a, int b){return a + b; });
    auto t = dv.Execute<decltype(y)>("aa", 3, 4);

    Tdd a;
    dv.Register<int>("aa", [&a](int x){return a.Test(x); });
    auto t1 = dv.Execute<int>("aa", 3);

    dv.Register<string>("aa", [](string x){return x; });
    auto t2 = dv.Execute<string>(std::move(string("aa")), std::move(string("test")));

    }

  • 相关阅读:
    mac-chrome下手动安装vue-devtools
    python生成随机数、随机字符串
    windows下基于sublime text3的nodejs环境搭建
    解决webstorm卡顿问题
    【更改表单元素默认样式】更改文件上传按钮样式
    JavaScript判断用户是通过电脑端还是移动端访问
    【转载自W3CPLUS】如何将页脚固定在页面底部
    【前端插件】图片上传插件收集
    AngularJS 表单提交后显示验证信息与失焦后显示验证信息
    【转】包管理器Bower详细讲解
  • 原文地址:https://www.cnblogs.com/qicosmos/p/3146402.html
Copyright © 2011-2022 走看看