实现一个简单的IOC容器

在软件开发中,控制反转(Inversion of Control,简称IoC)是一种设计原则,它可以用来减少程序中各个组件之间的耦合度。依赖注入(Dependency Injection,简称DI)是实现IoC的一种方式,它允许对象在创建时由外部提供其依赖项,而不是自己创建。本文将介绍如何实现一个简单的IoC容器,该容器可以管理对象的依赖关系,并在需要时提供对象实例。

获取类型代码

在存储一个类实现特定接口的方式之前,需要为这个类分配一个类型代码。在IOC容器实现中,使用了一个静态整数变量来指定下一个将被分配的类型ID,以及一个静态局部变量实例,可以通过调用GetTypeID方法来访问。

class IOCContainer { static int s_nextTypeId; public: template static int GetTypeID() { static int typeId = s_nextTypeId++; return typeId; } };

获取对象实例

有了类型ID之后,可以存储一个工厂对象来表示不知道如何创建对象的事实。为了在同一个集合中存储所有的工厂,选择了一个抽象基类,工厂将从这个基类派生,并实现一个捕获调用的函数。

class FactoryRoot { public: virtual ~FactoryRoot() {} }; std::map> m_factories; template class CFactory : public FactoryRoot { std::function()> m_functor; public: ~CFactory() {} CFactory(std::function()> functor) : m_functor(functor) {} std::shared_ptr GetObject() { return m_functor(); } }; template std::shared_ptr GetObject() { auto typeId = GetTypeID(); auto factoryBase = m_factories[typeId]; auto factory = std::static_pointer_cast>(factoryBase); return factory->GetObject(); }

注册实例

现在需要填充集合。实现了几种不同的方式:可能想要显式地提供一个函数对象,或者可能想要选择一个单一实例,或者按需创建新实例。

// 最基本的实现 - 注册一个函数对象 template void RegisterFunctor(std::function(std::shared_ptr... ts)> functor) { m_factories[GetTypeID()] = std::make_shared>([=]{ return functor(GetObject()...); }); } // 注册一个对象的实例 template void RegisterInstance(std::shared_ptr t) { m_factories[GetTypeID()] = std::make_shared>([=]{ return t; }); } // 提供一个函数指针 template void RegisterFunctor(std::shared_ptr(*functor)(std::shared_ptr... ts)) { RegisterFunctor(std::function(std::shared_ptr... ts)>(functor)); } // 一个工厂,将按需调用构造函数 template void RegisterFactory() { RegisterFunctor(std::function(std::shared_ptr... ts)>([](std::shared_ptr... arguments) -> std::shared_ptr { return std::make_shared(std::forward>(arguments)...); })); } // 一个工厂,将为每个请求返回一个实例 template void RegisterInstance() { RegisterInstance(std::make_shared(GetObject()...)); }

使用场景

现在已经准备好了。这里,将展示一个玩具使用场景,注册了两个对象——一个对象的构造函数将被调用并传入另一个类型的实例。将注意到必须在这里定义静态类型ID计数器,并给它一个初始值——使用什么值并不重要,但只想让它是一个容易识别的值。

IOCContainer gContainer; // 用非零数字初始化 int IOCContainer::s_nextTypeId = 115094801; class IAmAThing { public: virtual ~IAmAThing() {} virtual void TestThis() = 0; }; class IAmTheOtherThing { public: virtual ~IAmTheOtherThing() {} virtual void TheOtherTest() = 0; }; class TheThing : public IAmAThing { public: TheThing() {} void TestThis() { std::cout << "A Thing" << std::endl; } }; class TheOtherThing : public IAmTheOtherThing { std::shared_ptr m_thing; public: TheOtherThing(std::shared_ptr thing) : m_thing(thing) {} void TheOtherTest() { m_thing->TestThis(); } }; int main(int argc, const char* argv[]) { gContainer.RegisterInstance(); gContainer.RegisterFactory(); gContainer.GetObject()->TheOtherTest(); return 0; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485