проблема проектирования дженериков Java (конечный автомат)

Другие люди уже упомянули CRC32, но вот ссылка на реализация W3C CRC-32 для PNG как один из нескольких известных, уважаемых сайтов со ссылочной реализацией CRC.

(Несколько лет назад я пытался найти известный сайт с алгоритмом CRC или по крайней мере одним, который процитировал источник для его алгоритма, & почти отрывал мои волосы, пока я не нашел страницу PNG.)

17
задан Allen George 2 September 2011 в 19:01
поделиться

5 ответов

Для подхода B не используйте "красивую" хэш-карту. Вместо этого напишите обработчики разнородных безопасных типов контейнеров для объектов класса:

interface Handler<T extends Message> {
...}


interface Message {...}

interface HandlerContainer {

    <T extends Message> void register(Class<T> clazz, Handler<T> handler);

    <T extends Message> Handler<T> getHandler(T t);

}


class HandlerContainerImpl implements HandlerContainer {

    private final Map<Class<?>,Handler<?>> handlers = new HashMap<Class<?>,Handler<?>>();

    <T extends Message> void register(Class<T> clazz, Handler<T> handler) {
          if (clazz==null || handler==null) {
             throw new IllegalArgumentException();
          }
          handlers.put(clazz,handler);
    }

    //Type safety is assured by the register message and generic bounds
    @SuppressWarnings("unchecked")
    <T extends Message> Handler<T> getHandler(T t) {
            return  (Handler<T>)handlers.get(t.getClass());

    }

}
1
ответ дан 30 November 2019 в 14:48
поделиться

E с перечислениями, представляющими состояния и сообщения, вероятно, самый простой. Но он не очень расширяемый.

Использование шаблона «Посетитель» в классах состояний для отправки по типу сообщения выглядит как лучший из ваших вариантов. Имея выбор между instanceof и Visitor, я думаю, что Visitor немного чище (хотя и неудобно). Проблемы со стиранием типа действительно представляют собой заметную трудность, и обработка сообщения кажется несколько обратной. В типичной нотации конечного автомата в центре управления находятся состояния. Кроме того, вы можете сделать так, чтобы абстрактный класс Visitor для типов сообщений выдавал ошибку во всех состояниях, тем самым позволяя штатам бесплатно получать откат ошибок при недопустимых сообщениях.

C + Visitor был бы весьма аналогичен подходу, который я часто использую при реализации конечных автоматов на C или языках с функциями первого класса - «состояние» представлено указателем на функцию, обрабатывающую сообщения в текущем состоянии, с эта функция возвращает указатель на функцию следующего состояния (возможно, на себя). Цикл управления конечным автоматом просто выбирает следующее сообщение, передает его функции текущего состояния и обновляет понятие «текущее», когда оно возвращается.

2
ответ дан 30 November 2019 в 14:48
поделиться

Подход E. Забудьте о дженериках и используйте интерфейсы.

class Message { ... }
class State { ... }

class Machine {
  static State handle(State current, Message msg) {
    ...
  }
}

class CustomMessage extends Message { ... }
class CustomState extends State { ... }

class CustomMachine {
  static CustomState handle(CustomState current, CustomMessage msg) {
    // custom cases
    ...

    // default: generic case
    return Machine.handle(current, msg);
  }
}
2
ответ дан 30 November 2019 в 14:48
поделиться

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

public class MyState {
 @OnEntry
 public void startStuff() {
  ...
 }

 @OnExit() 
 public void cleanup() {
  ..
 } 
}

Есть еще несколько разработанных реализаций, я думаю, что версия Scientific Toolbox была хорошей, но я не могу найти нужную ссылку сейчас: http://mina.apache.org/introduction-to-mina-statemachine.html http://weblogs.java.net/blog/carcassi/archive/2007/02/finite_state_ma_1.html http://hubris.ucsd.edu/shared/manual.pdf

1
ответ дан 30 November 2019 в 14:48
поделиться

Подход F:

Забудьте о дженериках, если у вас нет шаблонов для конкретных типов. Определите пару интерфейсов для вашей желаемой системы, включая, возможно, что-то вроде

interface StateMachineState<R extends StateMachineState,T> {
    /* returns next state */
    R execute(T otherState); 
}

, и для конкретного конечного автомата используйте перечисления, расширяющие StateMachineState:

class OtherState {
    public double x1;
    public int i;
}

enum MyState extends StateMachineState<MyState,OtherState>
{
    FOO {
       MyState execute(OtherState otherState) { 
           otherState.x1 += 3.0;
           otherState.i++;
           return BAR;
       }
    },
    BAR {
       MyState execute(OtherState otherState) { 
           otherState.x1 -= 1.0;
           otherState.i--;
           return (i % 3 == 0) ? FOO : BAR;
       }
    },         
}

Затем вы можете сделать что-то вроде:

MyState state = MyState.FOO;
OtherState otherState = new OtherState();
otherState.i = 77;
otherState.x1 = 3.14159;
while (true)
{
    state = state.execute(otherState);
    /* do something else here */        
}

(предостережение: код не удваивается. проверен на наличие синтаксических ошибок)

-1
ответ дан 30 November 2019 в 14:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: