? **請(qǐng)注意!請(qǐng)注意!!!**今天講給大家講解非常“有用”的設(shè)計(jì)模式,解釋器模式!!!
? 設(shè)計(jì)模式有三大種類,一種是創(chuàng)建型模式,一種是結(jié)構(gòu)型模式,最后一種是行為性模式,那么解釋器模式屬于哪一種呢?帶領(lǐng)大家一起來了解學(xué)習(xí)解釋器模式!
? 本次介紹圍繞著以下五點(diǎn)展開。什么是解釋器模式?用來做什么?怎么做?有哪些優(yōu)點(diǎn)?有哪些不足?
? 解釋器模式顧名思義,就是用來定義和解釋。
? 給定一種特定語言,這個(gè)語言有特定的文法,解釋器可以解釋這個(gè)語言中的句子含義。即解釋器提供一種語言,如java,同時(shí)它也提供一種手段去解析java語言寫出來的代碼。
? 大家可能也會(huì)想到這就是類似編譯原理,一個(gè)算術(shù)表達(dá)式要經(jīng)過詞法分析,語法分析,構(gòu)建語法樹啥的;還有正則表達(dá)式;SQL解析,編譯器等等,其實(shí)都是解析式模式的一種實(shí)現(xiàn)。
? 那怎么做?一個(gè)是說要有像編譯原理中的終結(jié)符和非終結(jié)符,構(gòu)建一顆語法樹。同時(shí)需要有一個(gè)環(huán)境類,來管理輸入和輸出。
? 這里我們舉一個(gè)例子,輸入一個(gè)表達(dá)式a+b-c+d-e,同時(shí)給這5個(gè)變量賦值,計(jì)算出它的值。那么使用解釋器模式要如何實(shí)現(xiàn)?
? 我們?yōu)榻忉屍鞫x一個(gè)抽象解釋類Expression,所有的流轉(zhuǎn)通過interpreter方法實(shí)現(xiàn)。
? 上下文管理輸入輸出使用一個(gè)HashMap
去實(shí)現(xiàn)。
? 定義符號(hào)解釋類SymbolExpression
,加法解釋類AddExpreesion
,減法解釋類SubExpression
。
類圖:
具體代碼實(shí)現(xiàn):
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
|
public abstract class Expression { // map中攜帶了表達(dá)式中的變量名(key) 和 對(duì)應(yīng)的值(value) public abstract int interpreter(Map<String, Integer> var); } public class VarExpression extends Expression { // 表達(dá)式中對(duì)應(yīng)的變量名 String key; public VarExpression(String var) { this .key = var; } @Override public int interpreter(Map<String, Integer> var) { return var.get(key); } } public class SymbolExpression extends Expression { // +或-符號(hào) 左右兩邊的表達(dá)式 Expression var1; Expression var2; public SymbolExpression(Expression var1, Expression var2) { this .var1 = var1; this .var2 = var2; } @Override public int interpreter(Map<String, Integer> var) { // 實(shí)現(xiàn)抽象方法 // 該類不需要用到該方法 默認(rèn)返回0 return 0 ; } } public class AddExpression extends SymbolExpression { public AddExpression(Expression var1, Expression var2) { super (var1, var2); } @Override public int interpreter(Map<String, Integer> var) { return var1.interpreter(var) + var2.interpreter(var); } } public class SubExpression extends SymbolExpression { public SubExpression(Expression var1, Expression var2) { super (var1, var2); } @Override public int interpreter(Map<String, Integer> var) { return var1.interpreter(var) - var2.interpreter(var); } } public class Calculator { // 表達(dá)式 private Expression expression; // 解析出表達(dá)式 public Calculator(String expStr) { Stack<Expression> stack = new Stack<>(); Expression left, right = null ; char [] expStrCharArray = expStr.toCharArray(); for ( int i = 0 ; i < expStrCharArray.length; i++) { switch (expStrCharArray[i]) { case '+' : // 加法運(yùn)算 獲取左邊表達(dá)式 右邊數(shù)值 left = stack.pop(); right = new VarExpression(String.valueOf(expStrCharArray[++i])); stack.push( new AddExpression(left, right)); break ; case '-' : // 減法運(yùn)算 獲取左邊表達(dá)式 右邊數(shù)值 left = stack.pop(); right = new VarExpression(String.valueOf(expStrCharArray[++i])); stack.push( new SubExpression(left, right)); break ; default : // 表達(dá)式中的變量 stack.push( new VarExpression(String.valueOf(expStrCharArray[i]))); break ; } } // 最后會(huì)獲得被Expression包裝起來的一個(gè)表達(dá)式 this .expression = stack.pop(); } // 計(jì)算結(jié)果 public int run(Map<String, Integer> var) { return this .expression.interpreter(var); } } public class Client { public static void main(String[] args) throws IOException { String expStr = getExpStr(); Map<String, Integer> var = getValue(expStr); Calculator calculator = new Calculator(expStr); System.out.println( "運(yùn)算結(jié)果:" + expStr + "=" + calculator.run(var)); } //獲得表達(dá)式 public static String getExpStr() { return "a+b-c+d-e" ; } //獲得值映射 public static HashMap<String, Integer> getValue(String expStr) throws IOException { HashMap<String, Integer> map = new HashMap<>(); for ( char ch : expStr.toCharArray()) { if (ch != '+' && ch != '-' ) { if (! map.containsKey(String.valueOf(ch))) { System.out.print( "請(qǐng)輸入" + String.valueOf(ch) + "的值:" ); String in = ( new BufferedReader( new InputStreamReader(System.in))).readLine(); map.put(String.valueOf(ch), Integer.valueOf(in)); } } } return map; } } |
結(jié)果
/*
請(qǐng)輸入a的值:1
請(qǐng)輸入b的值:3
請(qǐng)輸入c的值:5
請(qǐng)輸入d的值:7
請(qǐng)輸入e的值:9
運(yùn)算結(jié)果:a+b-c+d-e=-3
*/
? 或許看代碼會(huì)有點(diǎn)云里霧里,希望大家能手動(dòng)敲一遍,或許會(huì)對(duì)整個(gè)過程有更進(jìn)一步的理解,在編碼的同時(shí)不斷思考,提升自我。
? 很容易發(fā)現(xiàn)解釋器模式是屬于行為性模式的一種,這種模式更關(guān)注對(duì)象之間的通信。
? 解釋器模式優(yōu)點(diǎn),結(jié)構(gòu)清晰,可拓展性好。但也有缺點(diǎn),一般用在比較底層場(chǎng)景,平常敲代碼可使用的場(chǎng)景比較少,并且解釋器模式采用的是遞歸的方式,當(dāng)語言比較長(zhǎng),性能不高;同時(shí)如果文法比較復(fù)雜,也需要更多的相應(yīng)解釋類。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注服務(wù)器之家的更多內(nèi)容!
原文鏈接:https://blog.csdn.net/KnightHONG/article/details/120693753