状态模式是怎样干掉case if的

有一个实例来辅助分析话会更方便,这里使用的实例是:编程找出文件中符合正则表达式 "alpha[alpha|digit]*" 和 "digit+" 的字符串。alpha 就是字母啦:[a-zA-Z];digit就是数字:[0-9]。

先画出DFA:

在上图中,状态只有三个(结束状态可以省略):开始状态、单词状态和数字状态。

接下来要用两种不同的方法来实现这个DFA,第一种是传统的 while&switch 大法,第二种是现在流行的设计模式中的状态模式。

为了方便比较,先抽象出一个名为Parser的接口,它提供了一个名为 parse 的方法,传统状态机状态机模式通过实现这个方法来完成对正则表达式的识别。传统状态机实现的类名叫ClassicalMachine,状态机模式的类名则叫PatternMachine。

Parser接口的定义:

1
2
3
public interface Parser {
  void parse() throws Exception ;
}

ClassicalMachine 类的实现非常简单,它在 parse() 方法里就完成了干完了一切:

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}

注意上面有一堆 case xxx: 和 if(xxx),如果DFA中有更多的状态和动作的话,case xxx: 会更多。

接下来实现状态模式类。从DFA图可以看出需要实现的动作只有三个,这三个动作分别在碰到字母、数字和其它字符时触发,因此可以定义状态抽象类如下:

1
2
3
4
5
abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
}<br>

为了方便判断字符是数字还是字母,再加上一个函数dispatch(),于是State类最终是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}

再看看上面的DFA图,发现状态只有三个,因此接下来从 State 派生出三个类对应这三个状态:

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
    
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
    
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}

万事具备,只欠东风了,剩下的只是将字符流作为燃料,来驱动状态机了:

1
2
3
4
5
6
7
8
9
public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
            
    }
}

 


上面啰啰嗦嗦写了一堆代码,目的就是要对比传统状态机的实现方式和状态模式的区别。传统的实现方式是使用一大块 if&switch 代码,比如说lua的lex;当然也可以对这段铁板代码进行拆分,python的lex就 是这么干的,但这样做仅仅只是将那些头痛的switch&if分散到了其它的函数而已,switch&if 和数量并没有减少。更多的条件判断语句会导致更复杂的逻辑,因此要让逻辑变得更简单, 得减少这些判断语句才行---状态模式办到了,它干掉了至少一半的判断语句。它是怎么做到的?

状态机的特点之一:状态是在运行时确定的,这刚好可以通过多态来实现。多态的特点:在运行时对对象进行动态绑定,绑定是由编译器或运行环境来完成的,无需手工参与,因此也可以说是现代越来越强大的编译器or运行环境干掉了switch&if。

附完整的代码:

ClassicalMachine.java:

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package bsg;
import java.io.BufferedReader;
import java.io.IOException;
import bsg.Main.Parser;
import com.sun.tools.hat.internal.parser.Reader;
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}
abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}
class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
    
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
    
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}
public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
            
    }
}

PatternMachine.java

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
package bsg;
import java.io.BufferedReader;
import bsg.Main.Parser;
public class PatternMachine implements Parser {
    private String mToken = "";
    private BufferedReader mFin;
    public PatternMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private StartState mStartState = new StartState();
    private KeywordState mKeywordState = new KeywordState();
    private NumberState mNumberState = new NumberState();
    //
    private State mState = mStartState;
    public State getState() {
        return mState;
    }
    public void setState(State state) {
        mState = state;
    }
    abstract class State {
        public abstract void isAlpha(char c);
        public abstract void isDigit(char c);
        public abstract void isOther(char c);
        public void dispatch(char c) {
            if (Character.isLetter(c)) {
                isAlpha(c);
            }
            else if (Character.isDigit(c)) {
                isDigit(c);
            }
            else {
                isOther(c);
            }
        }
    }
    
    class StartState extends State {
        public void isAlpha(char c) {
            setState( mKeywordState );
            mToken += c;
        }
        public void isDigit(char c) {
            setState( mNumberState );
            mToken += c;
        }
        public void isOther(char c) {
        }
    }
    
    class KeywordState extends State {
        public void isAlpha(char c) {
            mToken += c;
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Keyword: " + mToken);
            mToken = "";
        }
    }
    
    class NumberState extends State {
        public void isAlpha(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
    }
    
    @Override
    public void parse() throws Exception {
        while (true) {
            int ch = mFin.read();
            if (-1 == ch) break;
            char c = (char)ch;
            mState.dispatch( c );
            
        }
    }
}
package bsg;
import java.io.BufferedReader;
import java.io.IOException;
import bsg.Main.Parser;
import com.sun.tools.hat.internal.parser.Reader;
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}
abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}
class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
    
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
    
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}
public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
            
    }
}<br>

Main.java

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
package bsg;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class Main {
    public interface Parser {
        void parse() throws Exception ;
    }
    
    public static void main(String[] args) {
        if (0 == args.length) return;
        BufferedReader fin = null;
        try {
            fin = new BufferedReader( new FileReader(args[1] ) );
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        
        Parser parser = null;
        if (args[0].equals("cla")) {
            parser = new ClassicalMachine( fin );
        } else if (args[0].equals("pat")){
            parser = new PatternMachine( fin );
        }
        
        long beg = System.currentTimeMillis();
        try {
            parser.parse();
            fin.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis() - beg;
        System.out.println("" + end);
    }
}
package bsg;
import java.io.BufferedReader;
import bsg.Main.Parser;
public class PatternMachine implements Parser {
    private String mToken = "";
    private BufferedReader mFin;
    public PatternMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private StartState mStartState = new StartState();
    private KeywordState mKeywordState = new KeywordState();
    private NumberState mNumberState = new NumberState();
    //
    private State mState = mStartState;
    public State getState() {
        return mState;
    }
    public void setState(State state) {
        mState = state;
    }
    abstract class State {
        public abstract void isAlpha(char c);
        public abstract void isDigit(char c);
        public abstract void isOther(char c);
        public void dispatch(char c) {
            if (Character.isLetter(c)) {
                isAlpha(c);
            }
            else if (Character.isDigit(c)) {
                isDigit(c);
            }
            else {
                isOther(c);
            }
        }
    }
    
    class StartState extends State {
        public void isAlpha(char c) {
            setState( mKeywordState );
            mToken += c;
        }
        public void isDigit(char c) {
            setState( mNumberState );
            mToken += c;
        }
        public void isOther(char c) {
        }
    }
    
    class KeywordState extends State {
        public void isAlpha(char c) {
            mToken += c;
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Keyword: " + mToken);
            mToken = "";
        }
    }
    
    class NumberState extends State {
        public void isAlpha(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
    }
    
    @Override
    public void parse() throws Exception {
        while (true) {
            int ch = mFin.read();
            if (-1 == ch) break;
            char c = (char)ch;
            mState.dispatch( c );
            
        }
    }
}
package bsg;
import java.io.BufferedReader;
import java.io.IOException;
import bsg.Main.Parser;
import com.sun.tools.hat.internal.parser.Reader;
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}
public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
    
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
    
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;
    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)   break;
            char c = (char)ch;
            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;
            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;
            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
    
}
abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}
class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
    
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
    
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}
public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
            
    }
}

http://obiwong.is-programmer.com/posts/19595.html

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓