Abstract
When the design requires an "Abstract Factory Pattern" like stated by the [GoF] including several products and over some product families, then setting up an IoC can become a bit tricky. Especially when the specific factory implementations need to be dispatched by runtime parameters and shared among some subsequent components.
Given the follwing API, i was trying to set up my IoC (Ninject in this case) to retrieve Configuration objects configured through a IConfigurationFactory. The configuration stores an IFactory instance whoose implementation is determined by a runtime parameter of type ProductFamily. Afterwards the product types created by the factory inside of the configuration should always match the requested ProductFamily. The subgraph, consisting of the Component class holds the same IFactory per Configuration.
public enum ProductFamily { A, B }
public interface IProduct1 { }
public interface IProduct2 { }
public interface IFactory
{
IProduct1 CreateProduct1();
IProduct2 CreateProduct2();
}
public class Configuration
{
public readonly IFactory factory;
public readonly Component component;
public Configuration(IFactory factory, Component component)
{
this.factory = factory;
this.component = component;
}
}
public class Component
{
public IFactory factory;
public Component(IFactory factory) { this.factory = factory; }
}
public interface IConfigurationFactory
{
Configuration CreateConfiguration(ProductFamily family);
}
Tests
To clarify the intended behaviour i have added my test code writte in vstest. But forehand some additions, thanks to @BatterBackupUnit for asking these nitty details:
- The factories do only need the
ProductFamilyas a parameter to choose between the implementations, nothing else - Every
Configurationand its subsequent objects like theComponent, share the same factory instance
So i hope this helps :)
[TestMethod]
public void TestMethod1()
{
var configFac = ComposeConfigurationFactory();
// create runtime dependent configs
var configA = configFac.CreateConfiguration(ProductFamily.A);
var configB = configFac.CreateConfiguration(ProductFamily.B);
// check the configuration of the factories
Assert.IsInstanceOfType(configA.factory.CreateProduct1(), typeof(Product1A));
Assert.IsInstanceOfType(configB.factory.CreateProduct1(), typeof(Product1B));
Assert.IsInstanceOfType(configA.factory.CreateProduct2(), typeof(Product2A));
Assert.IsInstanceOfType(configB.factory.CreateProduct2(), typeof(Product2B));
// all possible children of the configuration should share the same factory
Assert.IsTrue(configA.factory == configA.component.factory);
// different configurations should never share the same factory
var configA2 = configFac.CreateConfiguration(ProductFamily.A);
Assert.IsTrue(configA.factory != configA2.factory);
}
This qestion has already been solved therefore i removed all the unnecessary fluff.
Thanks to @BatteryBackupUnit for your time and effort Best regards
Isaias