Ваш IAction
интерфейс (не путать с Action Delegate) очень похож на реализацию Command Pattern . В прошлом, когда я хотел сгруппировать команды (.NET v1.0), я должен был создать шаблон Composite для создания составной команды или, в вашем случае, Composite Action. Таким образом, детали его реализации будут иметь метод Add, а Execute будет выглядеть примерно так:
public CompositeAction : IAction
{
private ActiondCollection Action;
void Add(Action action)
{
Action.Add(action);
}
void Execute()
{
foreach(Action action in Actions)
{
action.Execute();
}
}
}
Это соответствует вашей идее списка списков.
Вы можете сделать это, но поскольку Execute возвращает void, единственный способ остановить работу цепочки команд - это вызвать исключение или использовать какое-то странное соединение (обновление некоторого значения IsValid из DoesWebSiteExist и проверка этого значения в каждом действии)
Вместо этого вы можете реализовать Цепочку ответственности , которая будет обрабатывать это более четко.
Другая альтернатива: если вы можете изменить существующие методы так, чтобы они просто возвращали bool, вы можете без труда добиться желаемых результатов, используя Func
Хорошая вещь здесь - пока метод возвращает bool, он может участвовать в этой структуре. Плохо то, что он не реализуется через интерфейс, поэтому методы не имеют такой ясной цели, поэтому он имеет некоторый запах кода.
namespace Test
{
class Program
{
//Change this value to show how the Actions bail when you DoesWebsiteNotExists
//returns false
static bool isvalid = true;
static void Main(string[] args)
{
List<System.Func<bool>> MainActions = new List<System.Func<bool>>();
List<System.Func<bool>> CompositeActions = new List<System.Func<bool>>();
MainActions.Add(() => NonCompositeAction());
//Probably want a builder here.
CompositeActions.Add(() => DoesWebsiteNotExists());
CompositeActions.Add(() => CreatePhyiscalDir());
CompositeActions.Add(() => CreateVirDirectories());
CompositeActions.Add(() => CreateWebsite());
MainActions.Add(() => ExcuteCompositeActions(CompositeActions));
foreach (Func<bool> action in MainActions)
action.Invoke();
}
static bool ExcuteCompositeActions(List<System.Func<bool>> Actions)
{
bool Success = true;
foreach (Func<bool> action in Actions)
{
if (!action.Invoke())
{
Success = false;
break;
}
}
return Success;
}
static bool NonCompositeAction()
{
Console.WriteLine("NonCompositeAction");
return true;
}
static bool DoesWebsiteNotExists()
{
Console.WriteLine("DoesWebsiteExists");
return isvalid;
}
static bool CreatePhyiscalDir()
{
Console.WriteLine("CreatePhyiscalDir");
return true;
}
static bool CreateWebsite()
{
Console.WriteLine("CreateWebsite");
return true;
}
static bool CreateVirDirectories()
{
Console.WriteLine("CreateVirDirectories");
return true;
}
}
}
Что касается расстановки приоритетов, я бы сделал это заранее, а не наращивал и затем расставлял приоритеты.
Обновление Уточнять методы в List<Func<bool>
можно откуда угодно.
Например, если у вас был этот класс
public class CreatePhyiscalDir
{
public bool Execute()
{
Console.WriteLine("CreatePhyiscalDir");
return true;
}
}
Вы можете изменить вышеуказанное на
CreatePhyiscalDir cpd = new CreatePhyiscalDir();
CompositeActions.Add(() => DoesWebsiteExists());
CompositeActions.Add(() => cpd.Execute());
Это будет работать, пока ваш cpd находится в области видимости.
Я хотел бы подчеркнуть, что эта сила из List<Func<bool>
составляет ...
- Это позволяет вам создавать структуры из вызовов методов, которые возвращают bool, который может быть почти любым. Это особенно полезно в случае, когда у вас уже есть существующая кодовая база.
- Создает зависимость, что следующее действие не будет выполнено, если предыдущее не было успешным.
Но слабость - это ...
- Вы можете написать методы, которые
return true;
просто вписываются в структуру, которой иначе не было бы.
- Отношения между методами или классами не совсем ясны.
Таким образом, у вас есть три варианта фактической реализации Chain of Responsiblity или Pipeline, псевдо-Pipeline-реализации, такой как решение List<Func<bool>>
, или Composite Actionl, такой как SnOrfus. То, что вы выберете, вероятно, будет зависеть от того, что вы уже написали, и от того, сколько вы должны будете изменить.
Одна последняя мысль. Вы можете сначала решить, решает ли каждое действие, должно ли быть выполнено следующее действие, или решает циклический код. Это может сообщить, как вы реализуете.