【问题标题】:C#, patterns - many conditionsC#,模式 - 许多条件
【发布时间】:2016-08-07 03:36:40
【问题描述】:

我正在为我的问题寻找一个好的模式。

我有一些布尔变量:

条件1,条件2,条件3。

我还有一些动作,它们在课堂内的不同地方被调用:

动作1,动作2,动作3

当条件 1 和 2 为真时调用 Action1。 当条件 2 和 3 为真时调用 action2。 当所有条件都为真时调用动作 3。

当然,这只是问题的简化。我不想在每个地方都使用 if else 。这是非常不清楚的。

我一直在考虑状态,但我想这不是解决这个问题的最佳方法。

【问题讨论】:

  • 所以你想要一个逻辑结构,当你运行它时,按照你的解释?
  • 模式?设计模式不是条件语句 mate ;)
  • 制作一个静态方法来获取这些布尔变量并返回正确的操作...
  • @TusharGupta 除非我们谈论的是解释器模式。或命令。或复合。在所有这些样本中,其中一个样本构成了一个复杂的条件。但它们不适合这里
  • “当条件 1 和 2 为真时调用 Action1”。是不是也需要condition3为假?

标签: c# design-patterns pattern-matching conditional-statements


【解决方案1】:

一种选择是将条件逻辑包装在一个基类中,然后从它派生以执行实际操作。这是Command 模式和(我认为)Strategy 模式的变体:

class ActionState
{
  public bool Condition1{get;set;}
  public bool Condition2{get;set;}
  public bool Condition3{get;set;}
}

abstract class ActionDispatcher
{
  protected abstract void ExecuteAction1();
  protected abstract void ExecuteAction2();
  protected abstract void ExecuteAction2();

  public void Action1(ActionState state)
  {
    if(state.Condition1 && state.Condition2)
    {
      ExecuteAction1();
    }
  }

  public void Action2(ActionState state)
  {
    if(state.Condition2 && state.Condition3)
    {
      ExecuteAction2();
    }
  }

  public void Action3(ActionState state)
  {
    if(state.Condition1 && state.Condition2 && state.Condition3)
    {
      ExecuteAction3();
    }
  }

  public void AllActions(ActionState state)
  {
    // Execute all actions depending on the state
    Action1(state);
    Action2(state);
    Action3(state);
  }
}

【讨论】:

  • 我很想知道谁对 Command 的变体投了反对票?我们真的必须挖掘GOF副本并参考页面吗?
  • @AlexanderDerck 如果您只显示示例,那么您还没有阅读它。并且只知道模式的第三人称总结。模式不是代码,它们是问题、上下文、解决方案以及与其他模式的关系。当前语言(如 C#)的几个特性这些模式的实现。了解它们将帮助您以新的方式将它们结合起来
  • @PanagiotisKanavos 所以它是以一种不太特定于语言的形式编写的?这就是我需要知道的,因为我看到很多人推荐它:)
  • @AlexanderDerck 一些例子在 Smalltalk 中,一些在 C++ 中。没关系。 真正重要的是概念、问题的描述、解决方案等。一旦您了解了您要查找的内容,您就可以轻松地以您喜欢的语言找到各种模式的实现
  • 嗯,我想这就是我需要的。在这种情况下,可能无法删除 if 语句。不过,这将有助于保持代码更清晰。
【解决方案2】:

带有[Flags] 属性的enum 可能会帮助您,而不是单独的布尔值。请参阅 this answer 以获得非常好的解释 + 示例。

【讨论】:

  • 这应该是一条评论
【解决方案3】:

您的条件没有很好地定义,但听起来像是状态到动作的映射,其中一个状态由许多简单的条件定义,每个状态只有一个动作。那么为什么不实际那样表示呢?

这是一个简单的 LinqPad 示例:

void Main()
{   
    Dictionary<Cond, Action> d = new Dictionary<Cond, Action>()  
    {
        { new Cond(waterproof:true, shockproof:true, freezeproof:false), delegate() { "Action1".Dump(); } },
        { new Cond(waterproof:false, shockproof:true, freezeproof:true), delegate() { "Action2".Dump(); } },
        { new Cond(waterproof:true, shockproof:true, freezeproof:true), delegate() { "Action3".Dump(); } }
    };

    d[new Cond(true, true, false)]();
    d[new Cond(false, true, true)]();
    d[new Cond(true, true, true)]();
}

public class Cond : Tuple<bool, bool, bool>
{
    public Cond(bool waterproof, bool shockproof, bool freezeproof) : base(waterproof, shockproof, freezeproof)
    {
    }
}

输出:

Action1
Action2
Action3

Tuple&lt;&gt; 的子类是因为:

  1. 它使所有内容都更具可读性,而不是到处都有泛型参数。

  2. 您可以像我一样使用命名参数来使地图逻辑非常清晰。

  3. 如果您需要更复杂的逻辑,例如在每个状态中改变条件数量,您可以将其替换为自定义类。

在这种情况下,您可能需要覆盖 EqualsGetHashCode

(您显然不需要使用匿名委托;您只需将直接引用传递给您要使用的方法)

【讨论】:

    【解决方案4】:

    您可以实现访问者模式。但这取决于您的抽象级别和功能 Visitor Pattern Implementation example

    【讨论】:

    【解决方案5】:

    有一种方法可以在没有任何 if 子句的情况下实现它。

    您可以将此布尔值转换为整数,从而可以在字典中获取方法,例如:

    cond1 = false, cond2 = true, cond3 = false

    您可以将其转换为: 0 + 1 + 0 = 1

    然后,您将为您拥有的每个解决方案创建一个密钥,如下所示:

    public Class Action1: IAction;
    public Class Action2: IAction;
    public Class Action3: IAction;
    
    Dictionary<int, IAction> dict = new Dictionary<int, IAction>()
    {
        6, new Action1(); //110
        3, new Action2(); //011
        7, new Action3(); //111
    };
    

    IAction接口:

    public interface IAction
    {
        void execute();
    }
    

    在具体类中的每个方法execute() 中,您将实现每个动作。

    然后您将通过以下方式执行您的操作:

    key = //transform binary in decimal
    dict[key].execute();
    

    希望对您有所帮助。

    【讨论】:

      【解决方案6】:

      可能是扩展方法:

      public static void WhenTrue(this bool condition, Action action)
      {
          if (action == null)
              throw new ArgumentNullException("action");
      
          if (condition)
              action();
      }
      

      用法:

      (condition1 && condition2).WhenTrue(() => DoSomeWork(param1));
      

      但这只有在你有很多条件和很多动作来保持代码整洁时才有意义。

      【讨论】:

      • if(condition1 &amp;&amp; condition2) DoSomeWork(param1); 有什么好处?
      • 说实话,不是。但是,如果您将 void 更改为 bool 则可以链接...虽然仍然很愚蠢:) 也许 OP 可以基于此想到一些东西 =)
      猜你喜欢
      • 1970-01-01
      • 2012-04-15
      • 1970-01-01
      • 2011-11-17
      • 2016-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-22
      相关资源
      最近更新 更多