С#, шаблоны - множество условий

Я ищу хороший образец для своей проблемы.

У меня есть переменные bool:

условие1, условие2, условие3.

Также у меня есть некоторые действия, которые вызывается в разных местах внутри класса:

действие1, действие2, действий3

Действие 1 вызывается, когда выполняются условия 1 и 2. action2 вызывается, когда выполняются условия 2 и 3. Действие 3 вызывается, когда все условия верны.

Конечно, это просто упрощение проблемы. Я не хочу использовать, если еще в любом месте. Это ужасно непонятно.

Я думал о состоянии, но думаю, это не лучшее решение этой проблемы.

Ответ 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);
  }
}

Ответ 2

Вам может помочь enum с атрибутом [Flags] вместо отдельных булевых. См. этот ответ за очень хорошее объяснение + примеры.

Ответ 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<> заключается в следующем:

  • Это делает все гораздо более удобочитаемым, чем везде, где есть общие аргументы.

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

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

В этом случае вам, вероятно, придется переопределить Equals и GetHashCode.

(Вам явно не нужно использовать анонимных делегатов, вы можете просто передать прямую ссылку на метод, который хотите использовать)

Ответ 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));

Но это имеет смысл только тогда, когда у вас много условий и много действий, чтобы очистить код.