11.2节的对象工厂只能创建指定接口类型的对象,原因是它依赖了一个类型固定的对象构造器std::function<T*()>,这个function作为对象构造器只能创建T类型的对象,不能创建所有类型的对象。我们可以通过Any类来使map存放所有类型的对象。Any类的基本用法如下:
Any a = 1;
Any b = 1.25;
Any c = "string";
std::vector<Any> v = {a, b, c};
// 用的时候转换回来
if (a.Is<int>())
{
int i = a.AnyCast<int>();
}
if (b.Is<double>)
{
double j = b.AnyCast<double>();
}
通过Any擦除类型可以解决之前对象工厂不能创建所有类型对象的问题:
#include <string>
#include <unordered_map>
#include <memory>
#include <functional>
using namespace std;
#include "Any.hpp"
class IocContainer
{
public:
IocContainer() {}
~IocContainer() {}
// 注册需要创建对象的构造函数
template<class T, typename Depend>
void RegisterType(const string& strKey)
{
// 注意,这里创建的是依赖的对象!不再是创建对象!
// 通过闭包擦除了Depend参数类型
std::function<T*()> function = []{ return new T(new Depend()); };
RegisterType(strKey, function);
}
// 根据唯一标识查找对应的构造函数,并创建指针对象
template<class T>
T* Resolve(const string& strKey)
{
if (m_creatorMap.find(strKey) == m_creatorMap.end())
{
return nullptr;
}
Any resolver = m_creatorMap[strKey];
// 将查找到的Any转换为function
std::function<T*()> function = resolver.AnyCast<std::function<T*()>>();
return function();
}
// 创建智能指针对象
template<class T>
std::shared_ptr<T> ResolveShared(const string& strKey)
{
T* ptr = Resolve<T>(strKey);
return std::shared_ptr<T>(ptr);
}
private:
void RegisterType(const string& strKey, Any constructor)
{
if (m_creatorMap.find(strKey) != m_creatorMap.end()) {
throw std::invalid_argument("this key has already exist!");
}
// 通过Any擦除不同类型的构造器
m_creatorMap.emplace(strKey, constructor);
}
private:
unordered_map<string, Any> m_creatorMap;
};
测试代码如下:
struct Base
{
virtual ~Base();
virtual void Func();
};
struct DerivedB : public Base
{
void Func() override
{
cout << "call func in DerivedB" << endl;
}
};
struct DerivedC : public Base
{
void Func() override
{
cout << "call func in DerivedC" << endl;
}
};
struct DerivedD : public Base
{
void Func() override
{
cout << "call func in DerivedD" << endl;
}
};
struct A
{
A(Base* ptr) : m_ptr(ptr)
{
}
~A()
{
if (m_ptr != nullptr)
{
delete m_ptr;
m_ptr = nullptr;
}
}
void Func()
{
m_ptr->Func();
}
private:
Base* m_ptr;
};
void TestIOC()
{
IocContainer ioc;
// 配置依赖关系
ioc.RegisterType<A, DerivedB>("B");
ioc.RegisterType<A, DerivedC>("C");
ioc.RegisterType<A, DerivedD>("D");
auto pb = ioc.ResolvedShared<A>("B");
pb->Func();
auto pc = ioc.ResolvedShared<A>("C");
pc->Func();
return 0;
}
输出结果:
call func in DerivedB
call func in DerivedC
改进后,当前对象工厂可以创建所有无参接口类型的对象。对于创建带参数的对象,可以用可变参数模板来优化。