【问题标题】:What design pattern to use for generating multiple simulations?使用什么设计模式来生成多个模拟?
【发布时间】:2016-08-23 18:01:13
【问题描述】:

我有一个在特定高度和特定温度下运行的模拟:

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

但是,在这种情况下,子模拟的 Generate() 方法偏离了 Step1、Step2、Step3 的顺序:

  • 如果指定了多个温度,则只需对所有子模拟执行一次Step2(),而不是每个温度(即每个多重模拟一次)。
  • 如果指定了多个高度,则:
    • Step1() 首先针对所有子模拟进行预计算。
    • Step2, Step3,..etc 然后被执行。
  • 可以进行具有多个高度和多个温度的宏大模拟。这意味着需要满足以上两个条件。

一般说明

  • 一个步骤的实现被封装在IStep中,它实现了IGeneratable。例如,模拟可以返回一个步骤列表。
  • 步骤数可能相当大。

我一直在尝试使用装饰器模式,但没有成功。

我正在寻找一种具有可扩展解决方案的合适模式,该解决方案可以处理单个模拟和多个模拟的生成。

谢谢。

【问题讨论】:

  • 一个抽象一个或多个模拟的模拟接口,听起来像Composite

标签: design-patterns decorator simulation builder composite


【解决方案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 步,我将简单地调用一个接收此复合作为参数的单例,因此对于这组模拟将只有一个 step2。

【讨论】:

    【解决方案2】:

    你的任务不是那么小,所以答案不是单一的设计模式,而是多个。我个人不会强调模式,而是强调直观和意图揭示的实现(例如,我在这里写过:http://www.tutisani.com/software-architecture/intuitive-object-models.html)。我认为你的设计不是直观的和自我描述的,所以你没有通过提出你提出的问题来解决正确的问题。

    无论如何,既然您要求确定设计模式,我也会帮助您。

    • 事实上,所有派生类型(特别是接口)都实现了 IGeneratable,即称为 Super Type 设计模式。
    • 正如一些人所建议的,包含其他模拟的模拟是Composite 模式。但是,它并不完全准确,因为 IMultiSimulation 没有实现 ISimulation。无论如何,这是某种复合,因为父母和孩子都至少实现了 IGeneratable。
    • IStep 听起来像 Strategy 模式,但我猜你没有正确实现它。

    现在,我想建议您重新考虑您的设计方法,因为您的界面不直观。以下是我看到的问题,您需要重新思考:

    • ISimulation 具有高度和温度,还具有 Generate()。 Generate() 很可能应该使用 Height 和 Temperature - 这就是我理解您的描述的方式,但这不是表达它的正确方式。如果 Generate() 取决于高度和温度,则将它们作为参数传递,并且不要将它们定义为属性。此外,接口可以更好地表达行为,而不是状态。属性代表状态,我将其表示为一个类,而不是一个接口。
    • 如果仿真要执行步骤,请不要在 ISimulation 本身上定义它们 - 这又不是那么直观的设计。将它们作为参数传递,这将使其成为一种策略设计模式(这就是我在上面说它没有正确实现的原因)。

    我会走得更远,但我不知道整体情况。从您所表达的内容来看,您提出的实现是不正确的。请重新考虑。

    【讨论】:

      【解决方案3】:

      接口:

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

      典型的多重仿真生成:

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

      典型的 ISimulation 生成:

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

      ISimulation 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),以防您的逻辑过于复杂。 但是,在您的情况下,我相信您应该使用像此代码示例这样的复合模式变体。

      编辑:Here 另一个您可能会使用的有趣模式

      【讨论】:

        【解决方案4】:

        在我看来,有一个非常具体的用例需要实现,所以我建议使用一个包含 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();
                 }
            }
        }
        

        【讨论】:

        • 这行不通,因为 GenerateStep2() 应该只运行一次。
        猜你喜欢
        • 1970-01-01
        • 2011-08-13
        • 1970-01-01
        • 2017-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多