深入理解Java設(shè)計(jì)模式之解釋器模式
一、什么是解釋器模式
定義:給定一個(gè)語(yǔ)言,定義一個(gè)文法的一種表示, 并定義一個(gè)解釋器, 這個(gè)解釋器使用該表示來(lái)解釋語(yǔ)言中的句子。
解釋器模式所涉及的角色如下所示:
(1)抽象表達(dá)式(Expression)角色:聲明一個(gè)所有的具體表達(dá)式角色都需要實(shí)現(xiàn)的抽象接口。這個(gè)接口主要是一個(gè)interpret()方法,稱(chēng)做解釋操作。
(2)終結(jié)符表達(dá)式(Terminal Expression)角色:實(shí)現(xiàn)了抽象表達(dá)式角色所要求的接口,主要是一個(gè)interpret()方法;文法中的每一個(gè)終結(jié)符都有一個(gè)具體終結(jié)表達(dá)式與之相對(duì)應(yīng)。比如有一個(gè)簡(jiǎn)單的公式R=R1+R2,在里面R1和R2就是終結(jié)符,對(duì)應(yīng)的解析R1和R2的解釋器就是終結(jié)符表達(dá)式。
(3)非終結(jié)符表達(dá)式(Nonterminal Expression)角色:文法中的每一條規(guī)則都需要一個(gè)具體的非終結(jié)符表達(dá)式,非終結(jié)符表達(dá)式一般是文法中的運(yùn)算符或者其他關(guān)鍵字,比如公式R=R1+R2中,“+"就是非終結(jié)符,解析“+”的解釋器就是一個(gè)非終結(jié)符表達(dá)式。
(4)環(huán)境(Context)角色:這個(gè)角色的任務(wù)一般是用來(lái)存放文法中各個(gè)終結(jié)符所對(duì)應(yīng)的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些信息需要存放到環(huán)境角色中,很多情況下我們使用Map來(lái)充當(dāng)環(huán)境角色就足夠了。
二、解釋器模式的使用場(chǎng)景
1.當(dāng)有一個(gè)語(yǔ)言需要解釋執(zhí)行,并且你可將該語(yǔ)言中的句子表示為一個(gè)抽象語(yǔ)法樹(shù),可以使用解釋器模式。而當(dāng)存在以下情況時(shí)該模式效果最好
2.該文法的類(lèi)層次結(jié)構(gòu)變得龐大而無(wú)法管理。此時(shí)語(yǔ)法分析程序生成器這樣的工具是最好的選擇。他們無(wú)需構(gòu)建抽象語(yǔ)法樹(shù)即可解釋表達(dá)式,這樣可以節(jié)省空間而且還可能節(jié)省時(shí)間。
3.效率不是一個(gè)關(guān)鍵問(wèn)題,最高效的解釋器通常不是通過(guò)直接解釋語(yǔ)法分析樹(shù)實(shí)現(xiàn)的,而是首先將他們裝換成另一種形式,例如,正則表達(dá)式通常被裝換成狀態(tài)機(jī),即使在這種情況下,轉(zhuǎn)換器仍可用解釋器模式實(shí)現(xiàn),該模式仍是有用的
三、解釋器模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1. 可以很容易地改變和擴(kuò)展方法, 因?yàn)樵撃J绞褂妙?lèi)來(lái)表示方法規(guī)則, 你可以使用繼承來(lái)改變或擴(kuò)展該方法。
2.也比較容易實(shí)現(xiàn)方法, 因?yàn)槎x抽象語(yǔ)法樹(shù)總各個(gè)節(jié)點(diǎn)的類(lèi)的實(shí)現(xiàn)大體類(lèi)似, 這些類(lèi)都易于直接編寫(xiě)。
3.解釋器模式就是將一句話(huà),轉(zhuǎn)變?yōu)閷?shí)際的命令程序執(zhí)行而已。 而不用解釋器模式本身也可以分析, 但通過(guò)繼承抽象表達(dá)式的方式, 由于依賴(lài)轉(zhuǎn)置原則, 使得文法的擴(kuò)展和維護(hù)都帶來(lái)的方便。
缺點(diǎn):
解釋器模式為方法中的每一條規(guī)則至少定義了一個(gè)類(lèi), 因此包含許多規(guī)則的方法可能難以管理和維護(hù)。 因此當(dāng)方法非常復(fù)雜時(shí), 使用其他的技術(shù)如 語(yǔ)法分析程序 或 編譯器生成器來(lái)處理。
四、解釋器模式的實(shí)現(xiàn)
音樂(lè)解釋器
演奏內(nèi)容類(lèi)(Context)
//演奏內(nèi)容類(lèi)(Context) class PlayContext { //演奏文本 private string text; public string PlayText { get { return text; } set { text = value; } } }
表達(dá)式類(lèi)(AbstractExpression)
//表達(dá)式類(lèi)(AbstractExpression) abstract class Expression { //解釋器 public void Interpret(PlayContext context) { if (context.PlayText.Length == 0) return; string playKey = context.PlayText.Substring(0, 1); context.PlayText = context.PlayText.Substring(2); double playValue = Convert.ToDouble(context.PlayText.Substring(0, context.PlayText.IndexOf(" "))); context.PlayText = context.PlayText.Substring(context.PlayText.IndexOf(" ") + 1); Excute(playKey, playValue); } //執(zhí)行 public abstract void Excute(string key, double value); }
音符類(lèi)(TerminaExperssion)
//音符類(lèi)(TerminaExperssion) class Note : Expression { public override void Excute(string key, double value) { string note = ""; switch (key) { case "C": note = "1"; 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; } } } //音符類(lèi)(TerminaExperssion) class Scale : Expression { public override void Excute(string key, double value) { string scale = ""; switch ((int)value) { case 1: scale = "低音"; break; case 2: scale = "中音"; break; case 3: scale = "高音"; break; } } }
客戶(hù)端代碼
class Program { //客戶(hù)端代碼 static void Main(string[] args) { PlayContext context = new PlayContext(); context.PlayText = "O 2 E 0.5 G 0.5 A 3 E 0.5"; Expression expression = null; try { while (context.PlayText.Length > 0) { string str = context.PlayText.Substring(0, 1); switch (str) { case "O": expression = new Scale(); break; case "P"://當(dāng)首字母為CDEFGAB及休止符P時(shí),實(shí)例化音符 expression = new Note(); break; } expression.Interpret(context); } } catch (Exception ) { throw; } Console.Read(); } }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- Java設(shè)計(jì)模式之解釋器模式
- 淺談Java解釋器模式
- Java設(shè)計(jì)模式之java解釋器模式詳解
- Java基于解釋器模式實(shí)現(xiàn)定義一種簡(jiǎn)單的語(yǔ)言功能示例
- Java設(shè)計(jì)模式之解釋器模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Java設(shè)計(jì)模式編程之解釋器模式的簡(jiǎn)單講解
- 解析Java的設(shè)計(jì)模式編程之解釋器模式的運(yùn)用
- JAVA設(shè)計(jì)模式之解釋器模式詳解
- Java實(shí)現(xiàn)自定義語(yǔ)言和表達(dá)式解析的解釋器模式
相關(guān)文章
Java實(shí)現(xiàn)Word/Pdf/TXT轉(zhuǎn)html的實(shí)例代碼
本文主要介紹了Java實(shí)現(xiàn)Word/Pdf/TXT轉(zhuǎn)html的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02springboot pojo對(duì)象日期屬性的問(wèn)題
這篇文章主要介紹了springboot pojo對(duì)象日期屬性的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot使用AOP統(tǒng)一日志管理的方法詳解
這篇文章主要為大家分享一個(gè)干貨:超簡(jiǎn)潔SpringBoot使用AOP統(tǒng)一日志管理,文中的示例代碼講解詳細(xì),感興趣的小伙伴快跟隨小編一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05SpringBoot整合Redis實(shí)現(xiàn)token緩存
于token通常會(huì)被多次使用,我們需要把它保存到緩存中,以減少頻繁地訪(fǎng)問(wèn)數(shù)據(jù)庫(kù),本文主要介紹了SpringBoot整合Redis實(shí)現(xiàn)token緩存,感興趣的可以了解一下2024-02-02淺談Spring框架中@Autowired和@Resource的區(qū)別
最近review別人代碼的時(shí)候,看到了一些@Autowired不一樣的用法,覺(jué)得有些意思,下面這篇文章主要給大家介紹了關(guān)于Spring框架中@Autowired和@Resource區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-10-10springboot動(dòng)態(tài)加載jar包動(dòng)態(tài)配置實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于springboot動(dòng)態(tài)加載jar包動(dòng)態(tài)配置的相關(guān)資料,在項(xiàng)目開(kāi)發(fā)的過(guò)程中,有時(shí)候需要?jiǎng)討B(tài)靈活的加載某個(gè)jar包并執(zhí)行其里面的方法的時(shí)候,需要的朋友可以參考下2023-11-11MybatisPlus3.3.0沒(méi)有MybatisPlusInterceptor類(lèi)問(wèn)題的解決方法
項(xiàng)目使用的是mybatis-plus-extension3.3.0依賴(lài),然后在我使用分頁(yè)插件的時(shí)候,發(fā)現(xiàn)無(wú)法導(dǎo)入MybatisPlusInterceptor類(lèi)所以本文給大家介紹了MybatisPlus3.3.0沒(méi)有MybatisPlusInterceptor類(lèi)問(wèn)題的解決方法,需要的朋友可以參考下2023-12-12