• (原创)C++ IOC框架


    C++里面缺少一些有用的框架比如说AOP和IOC等,AOP框架的实现在前面的博文中已介绍了,现在介绍IOC框架。

    IOC即控制反转,它的思想是由IOC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码。IOC不仅仅用来解除对象创建的耦合性,还可以使我们能通过配置去创建我们需要的对象,这种灵活性在我们应用开发过程中是非常有用的。C#和Java中有很多IOC框架,遗憾的是C++中却鲜有IOC框架,本IOC框架填补了这个遗憾。

    IOC框架的实现原理:通过向IOC容器注册类型信息和一个唯一key,在创建时,根据类型信息和key从容器中创建一个实例。下面具体看实现代码:

    #include <string>
    #include <map>
    #include <memory>
    #include <functional>
    using namespace std;
    #include <Any>
    #include<NonCopyable>
    
    class IocContainer : NonCopyable
    {
    public:
        IocContainer(void){}
        ~IocContainer(void){}
    
        template <class T>
        void RegisterType(string strKey)
        {
            typedef T* I;
            std::function<I()> function = Construct<I, T>::invoke;
            RegisterType(strKey, function);
        }
    
        template <class I, class T, typename... Ts>
        void RegisterType(string strKey)
        {
            std::function<I* (Ts...)> function = Construct<I*, T, Ts...>::invoke;
            RegisterType(strKey, function);
        }
    
        template <class I>
        I* Resolve(string strKey)
        {
            if (m_creatorMap.find(strKey) == m_creatorMap.end())
                return nullptr;
    
            Any resolver = m_creatorMap[strKey];
            std::function<I* ()> function = resolver.AnyCast<std::function<I* ()>>();
    
            return function();
        }
    
        template <class I>
        std::shared_ptr<I> ResolveShared(string strKey)
        {
            auto b = Resolve<I>(strKey);
    
            return std::shared_ptr<I>(b);
        }
    
        template <class I, typename... Ts>
        I* Resolve(string strKey, Ts... Args)
        {
            if (m_creatorMap.find(strKey) == m_creatorMap.end())
                return nullptr;
    
            Any resolver = m_creatorMap[strKey];
            std::function<I* (Ts...)> function = resolver.AnyCast<std::function<I* (Ts...)>>();
    
            return function(Args...);
        }
    
        template <class I, typename... Ts>
        std::shared_ptr<I> ResolveShared(string strKey, Ts... Args)
        {
            auto b = Resolve<I, Ts...>(strKey, Args...);
    
            return std::shared_ptr<I>(b);
        }
    
    private:
        template<typename I, typename T, typename... Ts>
        struct Construct
        {
            static I invoke(Ts... Args) { return I(new T(Args...)); }
        };
    void RegisterType(string strKey, Any constructor)
        {
            if (m_creatorMap.find(strKey) != m_creatorMap.end())
                throw std::logic_exception("this key has already exist!");
    
            m_creatorMap.insert(make_pair(strKey, constructor));
        }
    
    private:
        unordered_map<string, Any> m_creatorMap;
    };

    使用说明:

    类型注册分成三种方式注册,一种是简单方式注册,它只需要具体类型信息和key,类型的构造函数中没有参数,从容器中取也只需要类型和key;另外一种简单注册方式需要接口类型和具体类型,返回实例时,可以通过接口类型和key来得到具体对象;第三种是构造函数中带参数的类型注册,需要接口类型、key和参数类型,获取对象时需要接口类型、key和参数。返回的实例可以是普通的指针也可以是智能指针。需要注意的是key是唯一的,如果不唯一,会产生一个断言错误,推荐用类型的名称作为key,可以保证唯一性,std::string strKey = typeid(T).name()。

    由于用到了C++11的可变模板参数,所以对编译器有要求,windows中需要vs2012的Microsoft Visual C++ Compiler Nov 2012 CTP;linux GCC4.7及以上。

    测试代码:

    struct ICar
    {
            virtual ~ICar(){}
            virtual void test() const = 0;
    };
    struct Bus : ICar
    {
            Bus(int i, float f) {};
            void test() const { std::cout << "Bus::test()"; }
    };
    
    class IX
    {
    public:
        IX(){}
        virtual ~IX(){}
    
        virtual void g()=0;
    private:
    
    };
    
    class X : public IX
    {
    public:
      void g() 
      {
        std::cout << "it is a test" << std::endl;
      }
    };    
    
    void TestMyIoc()
    {
            //简单注册,需要类型信息和key
        IocContainer ioc;
        ioc.RegisterType<X>("ss");
        ioc.RegisterType<X>("ss");//key重复,会报错
        auto ix = ioc.ResolveShared<X>("ss");
        ix->g();
    
            //简单注册,需要类型信息、接口类型和key
        ioc.SimpleRegisterType<IX, X>("ff");
        auto ix1 = ioc.ResolveShared<IX>("ff");
        ix1->g();
    
            //含参数的类型注册,需要类型信息、接口类型、参数类型和key
        ioc.RegisterType<ICar, Bus, int, float>("bus");
        int a=1;
        float b= 2.0;
        auto mycar = ioc.ResolveShared<ICar>("bus", a, b);
        mycar->test();
    }    

    测试结果:

    it is a test
    it is a test
    Bus::test()

     补充一点:当resolve的参数类型为指针类型时,直接将nullptr作为参数传入会报异常,应该讲nullptr强制转换为注册时的参数类型。

    ioc.Resolve<BaseAppChain>(str, (BaseAppChain*)nullptr);

  • 相关阅读:
    ssh-copy-id 的使用方法
    如何保证 docker daemon重启,但容器不重启
    vim设置golang语法高亮 (Centos)
    Error response from daemon: Error running DeviceCreate (createSnapDevice) dm_task_run failed
    Please supply the message using either -m or -F option.
    sudo: Sorry, you must have a tty to run sudo Error on a Linux and Unix
    vim plugins (vim 插件) 工具集
    OmniGraffle v6 注册码
    test
    Collections.addAll 为什么比collection.addall 快(转)
  • 原文地址:https://www.cnblogs.com/qicosmos/p/3035074.html
Copyright © 2020-2023  润新知