Статьи

Java Secret: Использование enum для построения конечного автомата

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

В этой статье я расскажу об отдельных особенностях enum в Java и соберу их вместе, чтобы сформировать конечный автомат.

Enum для класса Singleton и Utility
Вы можете использовать enum как Singleton или Utility очень просто.

1
2
3
4
5
6
enum Singleton {
    INSTANCE;
}
enum Utility {
    ; // no instances
}

Enum для реализации интерфейса
Вы также можете реализовать интерфейс в перечислении.

01
02
03
04
05
06
07
08
09
10
interface Named {
    public String name();
    public int order();
}
 
enum Planets implements Named {
    Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune;
    // name() is implemented automagically.
    public int order() { return ordinal()+1; }
}

Каждый экземпляр Enum — это отдельный подкласс
Вы можете переопределить поведение экземпляра. Это эффективно дает экземпляру другой подкласс перечисления с его собственной реализацией.

01
02
03
04
05
06
07
08
09
10
// from http://download.oracle.com/javase/1,5.0/docs/guide/language/enums.html
public enum Operation {
  PLUS   { double eval(double x, double y) { return x + y; } },
  MINUS  { double eval(double x, double y) { return x - y; } },
  TIMES  { double eval(double x, double y) { return x * y; } },
  DIVIDE { double eval(double x, double y) { return x / y; } };
 
  // Do arithmetic op represented by this constant
  abstract double eval(double x, double y);
}

Использование перечисления в качестве конечного автомата
Что вы можете сделать со всеми этими методами, так это создать оператор на основе перечисления.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
interface Context {
    ByteBuffer buffer();
    State state();
    void state(State state);
}
interface State {
    /**
       * @return true to keep processing, false to read more data.
     */
    boolean process(Context context);
}
enum States implements State {
    XML {
        public boolean process(Context context) {
            if (context.buffer().remaining() < 16) return false;
            // read header
            if(headerComplete)
                context.state(States.ROOT);
            return true;
        }
    }, ROOT {
        public boolean process(Context context) {
            if (context.buffer().remaining() < 8) return false;
            // read root tag
            if(rootComplete)
                context.state(States.IN_ROOT);
            return true;
        }
    }
}
 
public void process(Context context) {
    socket.read(context.buffer());
    while(context.state().process(context));
}

Используя этот подход, можно написать синтаксический анализатор XML, который может обрабатывать пакеты за 10 микросекунд. Это так эффективно, как вам нужно в большинстве случаев.

Ссылка: Java Secret: Использование enum для создания конечного автомата от нашего партнера по JCG Питера Лоури из Vanilla Java .

Статьи по Теме: