如何在C 14中实现支持模板协方差的通用工厂?
我希望实现这样的目标:
std::shared_ptr<Factory<BaseClass>> factory = std::make_shared<Factory<DerivedClass>>(); auto x = factory->create(arg1,arg2,arg3);
请注意,在factory-> create中,您可以将任何参数传递给DerivedClass构造函数.可以假设BaseClass构造函数和DerivedClass是相同的.
为了避免XY问题,我需要这个的原因是因为我想使用依赖注入(boost::di)来实现最大可测试性.
例如,如果有一个创建Socket实例的类A,我希望它依赖于Factory< ISocket>服务.在实际代码中,我注入了Factory< Socket>,在测试代码中,我注入了Factory< Mock< ISocket>>,所以我可以测试A类而不实际创建一个真正的套接字.
这是我目前的尝试:
template <typename T> struct BaseFactory { virtual std::unique_ptr<T> create() = 0; }; template <typename TInterface,typename TImplementation> struct Factory : public BaseFactory<TInterface> { virtual std::unique_ptr<TInterface> create() override { return std::make_unique<TImplementation>(); } };
目前的用法是这样的:
std::shared_ptr<BaseFactory<ISocket>> factory = std::make_shared<Factory<ISocket,Socket>>(); auto x = factory->create();
虽然不理想(你需要在Factory中指定基类),但这种用法对我来说很好,而且有效.
我需要添加的下一件事是对构造函数参数的支持.我试图添加variadic模板来创建:
template <typename ...TArgs> virtual std::unique_ptr<T> create() = 0;
…但看起来你不能拥有带模板的虚拟方法.
>我正朝着正确的方向前进吗?
>如果是,我应该如何在我的实现中添加对构造函数参数的支持?
谢谢!
解决方法
好的,我找到了一个解决方案,但它并不漂亮:
template <typename T,typename ...TArgs> struct BaseFactory { virtual std::unique_ptr<T> create(TArgs&&... args) = 0; }; template <typename TInterface,typename TImplementation,typename ...TArgs> struct Factory : public BaseFactory<TInterface,TArgs...> { virtual std::unique_ptr<TInterface> create(TArgs&&... args) override { return std::make_unique<TImplementation>(std::forward<TArgs>(args)...); } }; using ISocketFactory = BaseFactory<ISocket,int>; using SocketFactory = Factory<ISocket,Socket,int>; int main() { std::shared_ptr<ISocketFactory> socket_factory = std::make_shared<SocketFactory>(); std::unique_ptr<ISocket> socket = socket_factory->create(1234); socket->read(); socket->write(); }
我们的想法是在BaseFactory和Factory模板中传递实现类的构造函数参数.在这种情况下,Socket构造函数应该类似于:
Socket(int n);
你知道如何优化这个吗? (更少的样板代码)