vendredi 15 avril 2016

Implementing a factory for the Composite pattern

I have the following simulation data:

interface ISimulationData
{
    string Name { get; }
    int[] Heights { get; }
    int[] Temperatures { get; }
}

And the following interface for generation:

interface ISimulation
{
    void Generate();
}

Using the Composite pattern to represent single or multi-simulations:

interface ISimpleSimulation : ISimulation
{
    int Height { get; }
    int Temperature { get; }
}

interface IMultiSimulation : ISimulation
{
    IEnumerable<ISimulation> GetSimulations();
}

And I have the following factory interface:

interface ISimulationFactory
{
    ISimulation CreateSimulation(ISimulationData simulationData);
}

Concrete implementations for the simulation types:

class SimpleSimulation : ISimpleSimulation
{
    public int Height { get; set; }
    public int Temperature { get; set; }

    public SimpleSimulation(int height, int temperature)
    {
        Height = height;
        Temperature = temperature;
    }

    public void Generate()
    {
        //Height/temperature parameters used here.
    }
} 

abstract class MultiSimulation : IMultiSimulation
{
    public void Generate()
    {
        foreach (ISimulation subSimulation in GetSimulations())
        {
            subSimulation.Generate();
        }
    }

    public abstract IEnumerable<ISimulation> GetSimulations();
}

If more than one height is specified, then a simulation is generated for each height:

class MultiHeightsSimulation : MultiSimulation
{
    private readonly int[] _heights;

    public MultiHeightsSimulation(int[] heights)
    {
        _heights = heights;
    }

    public override IEnumerable<ISimulation> GetSimulations()
    {
        ISimulationFactory factory = new SimulationFactory();

        foreach (int height in _heights)
        {
            //yield return factory.CreateSimulation(???);
        }
    }
}

Similarly, if more than one temperature is specified, then a simulation is generated for each temperature:

class MultiTemperaturesSimulation : MultiSimulation
{
    private readonly int[] _temperatures;

    public MultiTemperaturesSimulation(int[] temperatures)
    {
        _temperatures = temperatures;
    }

    public override IEnumerable<ISimulation> GetSimulations()
    {
        ISimulationFactory factory = new SimulationFactory();

        foreach (int temperature in _temperatures)
        {
            //yield return factory.CreateSimulation(???)
        }
    }
}    

Concrete implementation for the factory:

class SimulationFactory : ISimulationFactory
{
    public ISimulation CreateSimulation(ISimulationData simulationData)
    {
        if (simulationData.Heights.Length > 1)
        {
            return new MultiHeightsSimulation(simulationData.Heights);
        }

        if (simulationData.Temperatures.Length > 1)
        {
            return new MultiTemperaturesSimulation(simulationData.Temperatures);
        }

        return new SimpleSimulation(simulationData.Heights[0], simulationData.Temperatures[0]);
    }
}

Now I'm confused as to how to proceed with the following:

  • Handling combined multi-height AND multi-temperature scenario?

I've only shown height and temperature, but there are many other parameters that behave the same way, so I'm really looking for a proper solution that handle those multi-X scenarios, with minimal coupling.

  • ISimulationFactory has only one method exposed, which takes ISimulationData.

Now, you can see that MultiHeightsSimulation and MultiTemperaturesSimulation are calling the factory to create (simple) simulations at a specific height/temperature. Currently, there are no such methods provided by the factory and I was wondering if it makes sense to expose those methods in the factory? Wouldn't that confuse the clients of ISimulationFactory who are not supposed to be aware of the implementation details of the factory?

Looking forward to hear your feedback. Thanks!

Aucun commentaire:

Enregistrer un commentaire