Справка по Java Design Pattern - PullRequest
       16

Справка по Java Design Pattern

1 голос
/ 21 декабря 2009

Здравствуйте. Я пытаюсь построить структуру из IAction объектов, которые будут выполняться в последовательности. Каждая реализация IAction будет выполнять свой метод processAction () , для которого он был реализован. Этот метод возвращает IAction , который в большинстве случаев сам по себе, но в некоторых случаях может быть указателем на другой IAction в Списке. Интерфейс IActionIterator создан для управления этим перемещением в списке. Вот интерфейс



public interface IAction {
    public IAction processAction();
}

pulbic interface IActionIterator {
    public IAction getFirstAction();
    public IAction getNextAction( IAction action );
}

Моя структура получит List и будет проходить по списку, выполняя processAction () каждого IAction класса. Вот как будет выглядеть цикл



  IActionIterator  iter = ... // created some how
  IAction action = iter.getFirstAction();
  do {
       IAction newAction = action.processAction();
       if( action.equals( newAction ) 
           action = iter.getNextAction( action );
       else 
           action = newAction;

  while( action != null  )  {

Таким образом, каждое IAction имеет свою реализацию для выполнения, и некоторые IAction имеют бизнес-логику, которая будет возвращать IAction в списке вместо выполнения следующего в список.

Я ожидаю некоторые классы IAction , которые будут выполняться, но для следующего IAction в списке потребуются результаты первого. Например, один из IAction выполняет запрос SQL, и результаты относятся к следующему IAction в списке.

Таким образом, мой вопрос заключается в том, как бы или я должен реализовать это в форме передачи информации IAction to IAction в моей разработанной платформе?

Ответы [ 8 ]

2 голосов
/ 21 декабря 2009

Звучит так, будто вы пытаетесь изобразить граф перехода состояний. Можете ли вы использовать FSM вместо того, чтобы пытаться свернуть свой собственный?

1 голос
/ 21 декабря 2009

Я думаю, что вам нужно сочетание двух шаблонов проектирования: Command и Chain of Responsibility .

В командах вы можете инкапсулировать параметры для действий и передавать данные между действиями. Вы можете записывать обработку параметров и даже выполнять отмену функций, если это необходимо. Фактически, каждый объект команды будет чем-то вроде контекста для текущей обработки действий.

Действия могут передавать управление друг другу, используя цепочку команд, где каждое действие имеет ссылку на следующее действие. После выполнения своей бизнес-логики действие вызывает следующее действие для обработки, предоставляя ему объект команды.

Чтобы сделать его расширяемым для различных классов действий, вы также можете использовать шаблонный метод шаблона при реализации цепочки ответственности. Таким образом, каждый класс действия будет подклассом некоторого супер действия, которое определит метод шаблона, в котором будет происходить некоторая предварительная обработка команды, например проверка аргументов и другие вещи. Затем будет вызван подкласс, и после этого метод шаблона передаст управление следующему действию в цепочке.

При использовании таких шаблонов вам не понадобится список действий и общий цикл для их обработки. Вы просто создаете цепочку действий, а затем вызываете метод процесса для первого действия в списке, предоставляя ему объект команды. Кроме того, при построении цепочки у вас также есть дополнительная свобода смешивать порядок действий, обрабатывая их так, как вы этого хотите. Не будет зависимости от порядка действий в списке.

Итак, в основном вам понадобятся следующие классы и интерфейсы:

public interface IAction {
     public void process (Command command);
}

public class SuperAction implements IAction {
     private IAction nextAction;

     public void process (Command command) {
           // Check command object

           processAction(command);

           if (nextAction != null)
                nextAction.process(command);
     }

     public abstract processAction(Command command);

     public void setNextAction(IAction action) {nextAction = action;}
}

public class ActionConstructor {
     public IAction constructActoinChain() {
           // construct chain and return first object
     }

}

И чтобы завершить это, вам нужно определить объект Command либо с методом execute, либо без. Если без метода execute, то Command будет просто контейнером параметров, которые передаются между действиями.

1 голос
/ 21 декабря 2009

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

1 голос
/ 21 декабря 2009

Это тип обстоятельств, когда следующий вид интерфейса действительно хорошо работает:

public interface IAction {
    void invoke(IActionRequest req, IActionResponse res);
}

Каждое действие получает свои входные данные (которые могут быть любыми) из объекта 'req'. В свою очередь, каждое действие имеет возможность сообщать результаты - опять же, с открытым концом - используя объект res.

И FWIW, структура, которую вы описываете, звучит очень похоже на некоторые существующие платформы. Посмотрите проект Cernunnos , где приведен пример проекта, который очень близок к тому, что вы предлагаете.

1 голос
/ 21 декабря 2009

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

Для более простого случая, когда требуется результат предыдущего действия

IActionIterator { публичный IAction getFirstAction (); public getFirstActionResult (); public IAction getNextAction (действие IAction); }

1 голос
/ 21 декабря 2009

Я никогда не делал этого, но, возможно, вы можете использовать интерфейс Serializable для передачи общей информации между действиями? Тогда Действия будут ожидать определенных видов данных и знать, что с ними делать.

1 голос
/ 21 декабря 2009

Измените возвращаемую подпись вашего getFirstAction() / getNextAction() на простой объект-держатель:

public class IActionResponse {
    List getResultList();
    IAction getReturnAction();
}
0 голосов
/ 22 декабря 2009

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

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

Одна тема, о которой я никого не слышал, - это типичный аспект рабочих процессов: асинхронная обработка. Часто вы хотите иметь возможность выполнять действия вплоть до определенной точки, а затем сохранять состояние рабочего процесса. Затем рабочий процесс может быть запущен для продолжения какого-либо события (то есть, пользователь входит в систему и принимает решение). Для этого вам потребуется слой данных, который может сохранять общее состояние рабочего процесса отдельно от данных, специфичных для приложения.

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

Надеюсь, это поможет.

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