給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。express
若是一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述爲一個簡單語言中的句子。這樣就能夠構建一個解釋器,該解釋器經過解釋這些句子來解決該問題。ide
容易改變和擴展文法,由於該模式使用類來表示文法規則,你可以使用繼承來改變或擴展該文法。也比較容易實現文法,由於定義抽象語法樹中各個節點的類的實現大致相似,這些類都易於直接編寫。code
解釋器模式爲文法中的每一條規則至少定義了一個類,所以包含許多規則的文法可能難以管理和維護。建議當文法很是複雜時,使用其餘的技術如語法分析或編譯器生成器來處理。blog
實現一個簡單的音樂解釋器。規則大體有:「C D E F G A B」分別表示「Do-Re-Mi-Fa-So-La-Ti」;音符長度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍,以此類推。解釋如下《上海灘》
繼承
/** * 演奏內容類 * Created by callmeDevil on 2019/12/15. */ public class PlayContext { // 演奏文本 private String text; // 省略 get set }
/** * 表達式類 * Created by callmeDevil on 2019/12/15. */ public abstract class Expression { // 解釋器 public void interpret(PlayContext context){ if (context.getText().length() == 0) { return; } else { // 此方法用於將當前演奏文本第一條命令得到命令字母和其參數值 // 例如:「O 3 E 0.5 G 0.5 A 3」,則 playKey 爲O,而playValue 爲3 String playKey = context.getText().substring(0, 1); context.setText(context.getText().substring(2)); double playValue = Double.parseDouble(context.getText().substring(0, context.getText().indexOf(" "))); // 得到playKey 和 playValue 後將其從演奏文本中移除 // 例如:「O 3 E 0.5 G 0.5 A 3」變成了「E 0.5 G 0.5 A 3」 context.setText(context.getText().substring(context.getText().indexOf(" ") + 1)); excute(playKey, playValue); } } // 抽象方法執行,不一樣的文法的子類,有不一樣的執行處理 public abstract void excute(String key ,double value); }
/** * 音符類 * Created by callmeDevil on 2019/12/15. */ public class Note extends Expression { @Override public void excute(String key, double value) { String note = ""; switch (key) { case "C": note = "1"; // 若是得到的 key 是C,則演奏1(do),是D則演奏2(Re),以此類推 break; case "D": note = "2"; break; case "E": note = "3"; break; case "F": note = "4"; break; case "G": note = "5"; break; case "A": note = "6"; break; case "B": note = "7"; break; } System.out.print(note + " "); } }
/** * 音階類 * Created by callmeDevil on 2019/12/15. */ public class Scale extends Expression { @Override public void excute(String key, double value) { String scale = ""; switch ((int) value) { case 1 : scale = "低音"; break; case 2: scale = "中音"; break; case 3: scale = "高音"; break; } System.out.print(scale + " "); } }
public class Test { public static void main(String[] args) { PlayContext context = new PlayContext(); // 音樂-上海灘 System.out.println("上海灘:"); context.setText("O 2 E 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 "); Expression expression = null; try { while (context.getText().length() > 0) { String string = context.getText().substring(0, 1); switch (string) { case "O": // 當首字母是O時,表達式實例化爲音階 expression = new Scale(); break; case "C": case "D": case "E": case "F": case "G": case "A": case "B": case "P": // 當首字母是CDEFGAB以及休止符P時,則實例化爲音符 expression = new Note(); break; } expression.interpret(context); } } catch (Exception e) { e.printStackTrace(); } } }
運行結果get
上海灘: 中音 3 6 3 5 2 3 5 6 高音 1 中音 6 5 1 3 2
增長一個文法,就是演奏速度,用「T」表示,毫秒爲單位,‘T 1000’表示每節拍一秒。編譯器
/** * 音速類 * Created by callmeDevil on 2019/12/15. */ public class Speed extends Expression{ @Override public void excute(String key, double value) { String speed; if (value < 500) { speed = "快速"; } else if (value >= 1000) { speed = "慢速"; } else { speed = "中速"; } System.out.print(speed + " "); } }
public class Test { public static void main(String[] args) { PlayContext context = new PlayContext(); // 音樂-上海灘 System.out.println("上海灘:"); // 增長速度的設置 context.setText("T 500 O 2 E 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 "); Expression expression = null; try { while (context.getText().length() > 0) { String string = context.getText().substring(0, 1); switch (string) { case "O": // 當首字母是O時,表達式實例化爲音階 expression = new Scale(); break; case "T": // 增長對T的判斷 expression = new Speed(); break; case "C": case "D": case "E": case "F": case "G": case "A": case "B": case "P": // 當首字母是CDEFGAB以及休止符P時,則實例化爲音符 expression = new Note(); break; } expression.interpret(context); } } catch (Exception e) { e.printStackTrace(); } } }
運行結果string
上海灘: 中速 中音 3 6 3 5 2 3 5 6 高音 1 中音 6 5 1 3 2