1. 程式人生 > >Java祕術:用列舉構建一個狀態機

Java祕術:用列舉構建一個狀態機

原文連結   作者:

綜述

Java中的enum比其他的語言中的都強大,這產生了很多令人驚訝的用法。本文中,我將列出Java中的enum的一些特性,然後將這些特性應用到一起構成一個狀態機。

Enum的單例和工具類用法

你可以非常簡單地用一個enum構建一個單例或者工具類。

</pre>
enum Singleton {
    INSTANCE;
}
enum Utility {
    ; // no instances
}

用enum實現一個介面

你也可以在一個enum中實現一個介面。

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例項,一個不同的子類

你可以過載一個enum例項的方法。這將高效的給一個enum的例項一個自己的實現。

// 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);
}

使用一個enum實現一個狀態機

用上邊的技術,你可以做的是建立一個基於狀態的enum。

在這個小例子中,解析器的狀態機處理一個ByteBuffer裡的原始的XML。每一個狀態都有自己的處理方法,如果沒有足夠的可用的資料,狀態機可以回來再次獲取更多的資料。狀態之間的每一次變換都被定義,所有狀態的程式碼在一個enum中。

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微秒內處理完資料包。大多數情況下,它跟你需要的一樣高效。