When you need to implement Abstract Factory, StructureMap offers a way to do it for you. Let's say you have
public interface IDummyService
{
string Name { get; }
}
with implementation
public class DummyService : IDummyService
{
public string Name { get; set; }
}
Now you declare an interface for your factory:
public interface ISimpleDummyFactory
{
IDummyService CreateDummyService();
}
All you need to do is to call CreateFactory
when configuring the container as shown below:
[Fact]
public void Simple_factory_creation()
{
var container = new Container(cfg =>
{
cfg.For<IDummyService>().Use<DummyService>();
cfg.For<ISimpleDummyFactory>().CreateFactory();
});
var factory = container.GetInstance<ISimpleDummyFactory>();
var component = factory.CreateDummyService();
component.ShouldNotBeNull();
component.ShouldBeOfType<DummyService>();
}
Default convention
As for now, Auto-factories support two types of methods:
- Methods to list all names of registered implementations.
- Methods to create object instances i.e. factory methods.
To declare a method that has to return the names of registered implementations, the method signature must satisfy the following conditions:
- The name has to start with
GetNames
- It must be a generic method.
- The method return type must be assignable from
List<string>
e.g.IList<string>
,IEnumerable<string>
Any other method that has the return type (i.e. doesn't return void
), is treated as a factory method. In addition, if the method name starts with GetNamed
, the first method argument is used as the name for the named instance. All the rest arguments are passed as explicit arguments to the implementation constructor.
It is much easier to see it on an example:
public interface IDummyFactory
{
// This method will return the names of all registered implementations of TService.
IList<string> GetNames<TService>();
// This method will just create the default IDummyService implementation.
IDummyService CreateDummyService();
// This method will just create the default IDummyService implementation and pass namePart1 and namePart2 as
// dependencies.
IDummyService CreateDummyService(string namePart1, string namePart2);
// This method will create IDummyService implementation with serviceName name.
IDummyService GetNamedDummyService(string serviceName, string namePart1, string namePart2);
// Generic methods are also allowed as factory methods.
TService CreateService<TService>();
// Something that is common for event-sourcing implementations.
IHandler<TMessage> CreateHandler<TMessage>();
}
Custom convention
If the default convention doesn't work for you, you can create and use your custom convention. All you need is to implement IAutoFactoryConventionProvider
and use the corresponding CreateFactory
overload. IAutoFactoryConventionProvider
has a single method to implement:
IAutoFactoryMethodDefinition GetMethodDefinition(MethodInfo methodInfo, IList<object> arguments);
IAutoFactoryMethodDefinition
is defined as follows:
public interface IAutoFactoryMethodDefinition
{
AutoFactoryMethodType MethodType { get; }
Type InstanceType { get; }
string InstanceName { get; }
ExplicitArguments ExplicitArguments { get; }
}