为Composite模式实现工厂

时间:2016-04-15 19:15:28

标签: .net design-patterns decorator factory composite

我有以下模拟数据:

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

以下用于生成的界面:

interface ISimulation
{
    void Generate();
}

使用复合模式表示单个或多个模拟:

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

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

我有以下工厂界面:

interface ISimulationFactory
{
    ISimulation CreateSimulation(ISimulationData simulationData);
}

模拟类型的具体实现:

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();
}

如果指定了多个高度,则会为每个高度生成模拟:

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(???);
        }
    }
}

同样,如果指定了多个温度,则会为每个温度生成模拟:

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(???)
        }
    }
}    

工厂的具体实施:

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]);
    }
}

现在我对如何进行以下操作感到困惑:

  • 处理组合的多高度和多温度场景?

我只显示了高度和温度,但是还有许多其他参数的行为方式相同,所以我真的在寻找一种能够处理这些多X场景的合适解决方案,并且耦合最小。

  • ISimulationFactory只展示了一种方法,需要ISimulationData

现在,您可以看到MultiHeightsSimulationMultiTemperaturesSimulation正在调用工厂在特定高度/温度下创建(简单)模拟。目前,工厂没有提供这样的方法,我想知道在工厂中公开这些方法是否有意义?这不会让那些不应该知道工厂实施细节的ISimulationFactory客户感到困惑吗?

期待听到您的反馈。谢谢!

1 个答案:

答案 0 :(得分:0)

您的模拟工厂已经接受ISimulationData参数,该参数包含您当前关注的两个变量的数组:

int[] Heights { get; }
int[] Temperatures { get; }

一种选择是让SimulationFactory为这些数组中的每个元素组合生成一个模拟(一种笛卡尔积)。因此,如果您只有一个高度和5个温度,那么您将隐含地拥有MultiTemperaturesSimulation。然而,您也可以传递5个高度和4个温度,在这种情况下,工厂将生成20个模拟(每个高度和温度组合一个)...

这可以很容易地适应处理更多尺寸,稍后再添加这些尺寸。所以你可以有3个湿度,4个高度和5个温度,这将导致3 x 4 x 5 = 60个模拟。

您可能想要添加一些代码以确保在这种情况下工厂的ISimulationData参数中的每个数组中至少有一个元素(因为如果任何数组的元素为零,那么你最终得到零模拟 - 这可能没有意义,应该导致ArgumentException。)