[11 使用C++11开发一个轻量级的IoC容器(工厂模式的应用及优化)] 11.4 通过Any和闭包来擦除类型 和 创建依赖的对象

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

改进后,当前对象工厂可以创建所有无参接口类型的对象。对于创建带参数的对象,可以用可变参数模板来优化。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值