-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Autowiring of factory methods #43
Comments
I could write it for one argument but I don't know how to write the generalisation to n arguments and I am not aware of a possible way to perform this trick. Maybe you could change your factory so that it gets injected a class FooFactory
{
FooFactory(std::shared_ptr< IBar >);
std::unique_ptr< IFoo > createInstance();
};
class ReliesOnFoo
{
ReliesOnFoo(std::shared_ptr< FooFactory >);
void doSomething()
{
auto foo = fooFactory->createInstance();
}
};
ContainerBuilder builder;
builder.registerType< Bar >().as< IBar >();
builder.registerType< FooFactory >();
auto container = builder.build();
auto reliesOnFoo = container->resolve< ReliesOnFoo >(); Would that work for you? |
Thank you for your reply! Unfortunately, I'm not convinced by your solution, as it forces the See running code on godbolt.org. Using this, one can now register a factory method taking any number of shared_ptrs simply using Note: currently, I'm overloading --Daniel Code Example: #include <Hypodermic/ContainerBuilder.h>
#include <iostream>
#include <type_traits>
struct IBar {};
struct Bar : IBar {};
struct IBoo {};
struct Boo : IBoo {};
struct IFoo {};
struct IFoo2 : IFoo {};
struct Foo : IFoo2
{
Foo(std::shared_ptr<IBar> bar, std::shared_ptr<IBoo> boo) {}
};
struct FooFactory
{
static std::unique_ptr<IFoo2> createInstance(std::shared_ptr<IBar> bar, std::shared_ptr<IBoo> boo)
{
std::cout << "Creating instance of Foo" << std::endl;
return std::make_unique<Foo>(bar, boo);
}
};
class ContainerBuilder : public Hypodermic::ContainerBuilder
{
public:
using Hypodermic::ContainerBuilder::ContainerBuilder;
template <class TCallable,
typename = std::enable_if_t<std::is_invocable_v<TCallable, Hypodermic::ComponentContext&>>>
auto& registerInstanceFactory(const TCallable& instanceFactory)
{
return Hypodermic::ContainerBuilder::registerInstanceFactory(instanceFactory);
}
template <class FactoryFuncT,
typename = std::enable_if_t<!std::is_invocable_v<FactoryFuncT, Hypodermic::ComponentContext&>>>
auto& registerInstanceFactory(FactoryFuncT factoryFunc)
{
return registerInstanceFactory([factoryFunc](Hypodermic::ComponentContext& ctxt) {
return FactoryDeducer<FactoryFuncT>::createInstance(factoryFunc, ctxt);
});
}
private:
// Declare FactoryDeducer
template <class Sig> struct FactoryDeducer;
// Specialize for functions R f(std::shared_ptr<...>)
template <class R, class ...Args>
struct FactoryDeducer<R(*)(std::shared_ptr<Args>...)>
{
using FactoryFuncT = R(*)(std::shared_ptr<Args>...);
static auto createInstance(FactoryFuncT factoryFunc, Hypodermic::ComponentContext& ctxt)
-> std::shared_ptr<typename R::element_type>
{
return factoryFunc(ctxt.resolve<Args>()...);
}
};
};
void main()
{
ContainerBuilder builder{};
builder.registerInstanceFactory(FooFactory::createInstance).as<IFoo>().asSelf();
auto container = builder.build();
auto foo = container->resolve<IFoo>();
} |
In order to achieve full dependency inversion, I don't want to expose the concrete classes from code modules, but rather factory methods creating concrete objects implementing a given interface. They look like this:
Unfortunately, registering the factory is very verbose:
(1) Would it be possible to provide auto-wiring for factory methods, just as for constructors, something likes this:
NOTE: the factories return
std::unique_ptr
notstd::shared_ptr
because they are IoC (Hypodermic) agnostic. Converting from the former to the later is trivial. But still, Hypodermic currently requires one to force that conversion (-> std::shared_ptr<IFoo>
). Would be nice if that was implicit.The text was updated successfully, but these errors were encountered: