С#, шаблоны - множество условий
Я ищу хороший образец для своей проблемы.
У меня есть переменные 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
.
(Вам явно не нужно использовать анонимных делегатов, вы можете просто передать прямую ссылку на метод, который хотите использовать)
Ответ 4
Вы можете реализовать шаблон посетителя. Но это зависит от вас абстракции уровня и ваших функций
Пример реализации шаблона посетителя
Ответ 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));
Но это имеет смысл только тогда, когда у вас много условий и много действий, чтобы очистить код.