本系列文档从属于:C++11应用实践系列
部分Demo和结论引用自<深入应用C++11代码优化与工程>这本书
是为了实现某种机制,让某一对象创建不再直接依赖于外部对象创建。外界通过需求灵活的配置这种机制创建对象,这种机制称为控制反转(Inversion of Control, IoC).
我们一般通过依赖注入,将对象创建的依赖关系注入目标对象的构造函数中!比如A对象依赖于B对象的关系注入到A类对象的构造函数中。
IoC实际上具有两种能力:
为了实现这个功能,我们需要解决几个问题:
#include <iostream>#include <string>#include <map>#include <functional>#include <memory>using namespace std;template<class T>class IocContainer{public:using FuncType = std::function<T*()>;//注册一个key对应的类型template<class ClassType>void registerType(string key){FuncType func = [] {return new ClassType(); };registerType(key, func);}//根据唯一标志查询对应的构造器 创建对象T* resolve(string key){if (m_map.find(key) == m_map.end()){return nullptr;}auto func = m_map[key];return func();}std::shared_ptr<T> resolveShared(string key){if (m_map.find(key) == m_map.end()){return nullptr;}auto func = m_map[key];return std::shared_ptr<T>(func());}private:void registerType(string key, FuncType type){if (m_map.find(key) != m_map.end()){throw std::invalid_argument('this key has exist');}m_map.emplace(key, type);}private:std::map<string, FuncType> m_map;};struct ICar{virtual ~ICar() {}virtual void test() const = 0;};struct Car : ICar{void test() const{cout << 'Car test' << endl;}};struct Bus : ICar{void test() const{cout << 'Bus test' << endl;}};int main(){IocContainer<ICar> ioc;ioc.registerType<Bus>('bus');ioc.registerType<Car>('car');std::shared_ptr<ICar> bus = ioc.resolveShared('bus');bus->test(); return 0;}
以上虽然可以创建无参数的派生对象,但存在几个问题:
####Any和闭包擦除类型
上面讲的Ioc容器必须要知道容器存储的数据类型,我们通过一个Any类型擦除这个限制。Any实现见:链接
class IocContainer{public://注册一个key对应的类型template<class T, class Depend, class =std::enable_if<!std::is_same<Depend, void>::value>::type>void registerType(string key){std::function<T*()> func = [] {return new T(new Depend()); };registerType(key, func);}//简单的对象工厂template<class T>void registerType(string key){std::function<T*()> func = [] {return new T(); };registerType(key, func);}//根据唯一标志查询对应的构造器 创建对象template<class T>T* resolve(string key){if (m_map.find(key) == m_map.end()){return nullptr;}Any func = m_map[key];//转换为合适的类型std::function<T*()> f = func.cast<std::function<T*()>>();return f();}template<class T>std::shared_ptr<T> resolveShared(string key){T* t = resolve<T>(key);return std::shared_ptr<T>(t);}private:void registerType(string key, Any func){if (m_map.find(key) != m_map.end()){throw std::invalid_argument('this key has exist');}m_map.emplace(key, func);}private:std::map<string, Any> m_map;};
测试程序如下:
struct ICar{virtual ~ICar() {}virtual void test() const {}};struct Car {void test() const{cout << 'Car test' << endl;}};struct Bus{void test() const{cout << 'Bus test' << endl;}};struct Base{virtual void func() {}virtual ~Base(){}};struct DerivedB : Base{virtual void func() {cout << 'derived b' << endl;}};struct DerivedA : Base{virtual void func() {cout << 'derived a' << endl;}};struct A{A(Base* ptr) : m_ptr(ptr) {}virtual void func() {m_ptr->func();}private:Base* m_ptr;};IocContainer ioc;ioc.registerType<A, DerivedA>('A');ioc.registerType<A, DerivedB>('B');auto pa = ioc.resolveShared<A>('A');auto pb = ioc.resolveShared<A>('B');pa->func();pb->func();cout << '-------------------' << endl;ioc.registerType<Bus>('bus');ioc.registerType<Car>('car');auto pbus = ioc.resolveShared<Bus>('bus');auto pcar = ioc.resolveShared<Car>('car');pbus->test();pcar->test();
测试结果如下:
这里的关键就是使用了lambda表达式擦除具体类型,然后将其赋值给Any类型。
###IoC支持可变参数
上面实现的IoC容器,依赖的对象构造函数都是无参数的,下面我们需要增加入参测试。
class IocContainer{public://注册一个key对应的类型template<class T, class Depend, typename ...Args>void registerType(string key){std::function<T*(Args...)> func = [] (Args...args){return new T(new Depend(args...)); };registerType(key, func);}//根据唯一标志查询对应的构造器 创建对象template<class T, typename...Args>T* resolve(string key, Args...args){if (m_map.find(key) == m_map.end()){return nullptr;}Any func = m_map[key];//转换为合适的类型std::function<T*(Args...)> f = func.cast<std::function<T*(Args...)>>();return f(args...);}template<class T, typename...Args>std::shared_ptr<T> resolveShared(string key, Args...args){T* t = resolve<T>(key, args...);return std::shared_ptr<T>(t);}private:void registerType(string key, Any func){if (m_map.find(key) != m_map.end()){throw std::invalid_argument('this key has exist');}m_map.emplace(key, func);}private:std::map<string, Any> m_map;};struct Base{virtual void func() {}virtual ~Base() {}};struct Derived : Base{Derived(int a, double d) :m_a(a), m_d(d) {}virtual void func() {cout << 'derived :'<<m_a + m_d << endl;}private:int m_a;double m_d;};struct A{A(Base* ptr) : m_ptr(ptr) {}virtual void func() {m_ptr->func();}private:Base* m_ptr;};//测试代码IocContainer ioc;ioc.registerType<A, Derived, int, double>('A');auto pa = ioc.resolveShared<A>('A', 1, 2.0);pa->func();
我们需要支持将接口和派生类的关系进行配置,这样后面就可以根据参数配置接口和派生类的关系。
主要修改的点就是判断继承关系,如果是派生类则直接创建对象。
//T和Depend没有继承关系template<class T, class Depend, typename ...Args>typename std::enable_if<!std::is_base_of<T, Depend>::value>::type //此时type为voidregisterType(string key){std::function<T*(Args...)> func = [] (Args...args){return new T(new Depend(args...)); };registerType(key, func);}//T和Depend有继承关系template<class T, class Depend, typename ...Args>typename std::enable_if<std::is_base_of<T, Depend>::value>::type //此时type为voidregisterType(string key){std::function<T*(Args...)> func = [](Args...args) {return new Depend(args...); };registerType(key, func);}struct Interface{virtual void func() {}virtual ~Interface() {}};struct Derived : Interface{Derived(int a, double d) :m_a(a), m_d(d) {}virtual void func() {cout << 'derived :'<<m_a + m_d << endl;}private:int m_a;double m_d;};//测试代码IocContainer ioc;ioc.registerType<Interface, Derived, int, double>('interface');auto pa = ioc.resolveShared<Interface>('interface', 1, 2.0);pa->func();
通过依赖注入的方式实现控制反转,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定。
由容器动态的将某种依赖关系注入到组件中,方式有很多种:C#和Java中支持构造函数、属性和方法的注入。由于C++不支持反射和标签,不能实现属性和方法的调用和注入,只能实现构造函数的依赖注入。
我们上面对象成功注册到对了Ioc容器,并且通过关键字关联,随后通过配置文件可以很容易实现上面的效果。
联系客服