Нужна идея о том, как обрабатывать переменные группы задач в приложении Winforms - PullRequest
3 голосов
/ 17 декабря 2010

Я изо всех сил пытаюсь разобраться с частями разрозненных действий в моем приложении. У меня в основном есть форма, которую пользователь выбирает для выполнения действий. Некоторые действия выполняются в одиночку и легко могут перейти в очередь, которую я выполнил в заказе. Однако для некоторых действий требуется несколько связанных действий, для которых основное действие требует, чтобы сначала выполнялись другие задачи:

Create Website
 - DoesWebsiteExists (Validation)
 - CreatePhyiscalDir 
 - CreateWebsite 
 - CreateVirDirectories

Все эти действия были разделены и не знают друг о друге.

Первоначально, перед тем как отделить Validation от действия, я передавал объект Settings, который содержит все связанные / необходимые настройки для выполнения каких-либо действий, и очередь, для которой я выполняю итерацию, и вызываю метод Execute () для каждого действия.

 Queue<IAction> Actions
    [0] = CreateDirectory.Execute()
    [1] = CreateWebsite.Execute()

Но теперь, когда я свел все эти действия вниз, я не уверен, как мне их собрать.

Будет ли у меня список списков? Где, если действие было отдельным действием, это был бы просто список из 1 элемента? И если бы это было действие, требующее 4 действий (4 разных объекта), это был бы список из 4 элементов?

Чтобы добавить туда дополнительный слой - есть вероятность, что иногда основное действие потребует действия или не зависит от выбора, выбранного в форме. Например, если пользователь выбрал создание пула приложений в IIS, он может быть в списке или нет и придумать способ расстановки приоритетов в списке.

Есть идеи?

Ответы [ 2 ]

3 голосов
/ 18 декабря 2010

Ваш 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> составляет ...

  1. Это позволяет вам создавать структуры из вызовов методов, которые возвращают bool, который может быть почти любым. Это особенно полезно в случае, когда у вас уже есть существующая кодовая база.
  2. Создает зависимость, что следующее действие не будет выполнено, если предыдущее не было успешным.

Но слабость - это ...

  1. Вы можете написать методы, которые return true; просто вписываются в структуру, которой иначе не было бы.
  2. Отношения между методами или классами не совсем ясны.

Таким образом, у вас есть три варианта фактической реализации Chain of Responsiblity или Pipeline, псевдо-Pipeline-реализации, такой как решение List<Func<bool>>, или Composite Actionl, такой как SnOrfus. То, что вы выберете, вероятно, будет зависеть от того, что вы уже написали, и от того, сколько вы должны будете изменить.

Одна последняя мысль. Вы можете сначала решить, решает ли каждое действие, должно ли быть выполнено следующее действие, или решает циклический код. Это может сообщить, как вы реализуете.

1 голос
/ 18 декабря 2010

Мне нравится решение, опубликованное Конрадом Фриксом, но я также предложу другой вариант:

Я сделал нечто подобное, и в моем случае я использовал шаблон цепи ответственности вместо набора действий.

Итак, в вашем случае я бы изменил ваш IAction на абстрактный базовый класс, который выглядит следующим образом:

public abstract SystemAction
{
    public SystemAction nextAction { get; set; }

    public void Execute()
    {
        this.ExecuteAction();
        if (this.nextAction != null)
            this.nextAction.Execute();
    }

    protected abstract void ExecuteAction();

    public SystemAction ThenDo(SystemAction action) 
    { 
        this.nextAction = action;
        return this.nextAction;
    }            
}

Чтобы ваше действие могло быть связано со следующим действием. Код клиента в итоге выглядит так:

SystemAction setupSite = new CreatePhyiscalDir();
setupsSite
    .ThenDo(new CreateWebsite())
    .ThenDo(new CreateVirDirectories());

setupSite.Execute();

Я бы не сказал, что это лучше, чем решение Конрада, но это другой вариант. Я эффективно его использую в своей системе (построение цепочек фильтров для механизма очередей).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...