Какой шаблон проектирования используется для создания нескольких симуляций?

У меня есть симуляция, которая работает на определенной высоте и определенной температуре:

interface IGeneratable
{
    string Name { get; }
    void Generate();
}    

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

Процесс Generate() для моделирования обычно включает в себя несколько этапов:

void Generate()
{
    Step1();
    Step2();
    Step3();
}

Теперь пользователь может указать несколько высот и/или несколько температур.

В этом случае генерируются множественные симуляции (субимоляции), по одному на каждую комбинацию высоты/температуры.

interface IMultiSimulation : IGeneratable
{
    ISimulation[] SubSimulations { get; }       
}

Однако в этом случае метод Sub-simulation Generate() отклоняется от порядка Step1, Step2, Step3:

  • Если указано несколько температур, то Step2() необходимо выполнить только один раз для всех подмодулей, а не для температуры (т.е. один раз для мультимоделирования).
  • Если указано несколько высот, то:
    • Step1() предварительно вычисляется сначала для всех под-симуляций.
    • Затем выполняются шаги Step2, Step3 и т.д.
  • Возможно иметь большое симуляцию с несколькими высотами и несколькими температурами. Это означает, что необходимо выполнить 2 вышеуказанных критерия.

Общие примечания

  • Этап реализации инкапсулирован в IStep, который реализует IGeneratable. Таким образом, для моделирования можно, например, вернуть список шагов.
  • Количество шагов может быть довольно большим.

Я пытаюсь использовать шаблон декоратора, но без успеха.

Я ищу подходящий шаблон с масштабируемым решением, которое будет обрабатывать генерацию одиночного моделирования, а также несколько симуляций.

Спасибо.

Ответ 1

В вашем случае я бы использовал композитный шаблон дизайна. Метод generate будет проверять, имеет ли он какие-либо компоненты. Если это не так, просто вызывается

void Generate()
{
    Step1();
    Step2();
    Step3();
}

но если у него есть компоненты, это означает, что он имеет несколько симуляций. Тогда код будет выглядеть примерно так:

void Generate()
{
if(this.simulations.Count==0)
{
  Step1();
  Step2();
  Step3();
}
else
 {
    if(multipleHeights)
    {
      precomputeStep1();
      if(multipleHeights)
      {
        createSingletonForStep2(this);
      }
      else
      {
        Step2();
      }
      Step3();
    }
  }
}

И для шага 2 я бы просто вызвал одноэлемент, который получает этот композит в качестве параметра, поэтому для этой группы симуляций будет только один шаг2.

Ответ 2

Интерфейсы:

interface IGeneratable
{
    string Name { get; }
    void Generate();
} 

interface IGeneratableOnce : IGeneratable
{
    bool HasRunned { get; set; }
}   

interface ISimulation : IGeneratable
{
    int Height { get; }
    int Temperature { get; }
    IMultiSimulation MultiSimulation{ get; }
    IGeneratable[] Steps{ get; }

}

interface IMultiSimulation : IGeneratable
{
    ISimulation[] SubSimulations { get; }       
}

Типичная генерация MultiSimulation:

void Generate(){
    for (ISimulation simulation in SubSimulations){
        simulation.Generate();
    }
}

Типичная генерация ISimulation:

void Generate(){
    for (IGeneratable step in Steps){
        step.Generate();
    }
}

Исимуляция Создайте, избегая второго шага дважды:

void Generate(){
    for (int i=0;i<Steps.Length;i++){
        IGeneratable step = Steps[i];
        if (i!=1){
            if (step is IGeneratableOnce && !(step as IGeneratableOnce).HasRunned){
                step.Generate();
                step.HasRunned = true;
            }
        }else{
            step.Generate();
        }
    }
}

Вы можете добавить несколько других флагов, если хотите, возможно, даже какой-то метод вроде CanRun (int Height, int Temperature), если ваша логика становится слишком сложной. Однако в вашей ситуации, я считаю, вы должны использовать составную вариацию шаблона, как этот образец кода.

EDIT: Здесь еще один интересный шаблон, который вы можете использовать

Ответ 3

Ваша задача не такая маленькая, поэтому ответ - это не один шаблон дизайна, а несколько. Я лично не стал бы акцентировать внимание на шаблонах, а скорее на интуитивной и интенциональной реализации (например, я написал об этом здесь: http://www.tutisani.com/software-architecture/intuitive-object-models.html). Я думаю, что ваш дизайн не является интуитивным и самоописательным, поэтому вы не решаете правильную проблему, задавая вопрос, который вы задали.

В любом случае, поскольку вы просите идентифицировать образцы дизайна, я также помогу вам в этом.

  • Факт, что все ваши производные типы (в частности, интерфейсы) реализуют IGeneratable, который называется шаблоном проектирования Super Type.
  • Как предполагалось, симуляция, содержащая другие симуляции внутри, представляет собой шаблон Composite. Однако это не совсем точно, так как IMultiSimulation не реализует ISimulation. В любом случае это какой-то составной компонент, поскольку как родитель, так и дети реализуют IGeneratable по крайней мере.
  • IStep звучит как шаблон Strategy, но, я думаю, вы не используете его правильно.

Теперь я хочу предложить вам пересмотреть свой подход к дизайну, потому что ваши интерфейсы не интуитивно понятны. Вот проблемы, которые я вижу, которые вам нужно передумать:

  • Исимуляция имеет высоту и температуру, а также имеет Generate(). Generate(), скорее всего, предполагается использовать Height and Temperature - то, как я понял ваше описание, но тогда это не правильный способ выразить это. Если Generate() зависит от высоты и температуры, передайте их как аргументы и не определяйте их как свойства. Кроме того, интерфейс может лучше выражать поведение, а не состояние. Свойства представляют состояние, которое я хотел бы выразить как класс, а не интерфейс.
  • Если симуляция будет выполнять шаги, не определяйте их сами по ISimulation - это опять не так интуитивно понятный дизайн. Передайте их как аргументы, и это сделает его шаблоном проектирования стратегии (почему я сказал выше, что он не реализован правильно).

Я бы пошел дальше, но я не знаю всей картины. Из того, что вы выразили, ваша представленная реализация неверна. Пожалуйста, подумайте.

Ответ 4

мне кажется, что существует очень конкретный прецедент для реализации, поэтому я предлагаю использовать класс, который будет включать в себя memlement для Generate() (надеюсь, я правильно понял требования)

class Simulation
{
    string Name { get; }
    int[] Heights { get; }
    int[] Temperatures { get; }

    void Generate() {
         for (int i = 0; i < Temperatures.Count; i++) {
             for (int j = 0; j < Heights.Count; j++) {
                  GenerateStep1();
             }
             GenerateStep2();
             GenerateStep3();
         }
    }
}