設計模式-行為型-解釋器模式

来源:https://www.cnblogs.com/az4215/archive/2019/10/11/11648518.html
-Advertisement-
Play Games

解釋器模式(Interpreter): 從名稱上來看看這個模式,個人的最初理解“解釋器”和Google的中英翻譯功能類似。如果有一天你去國外旅游去了,比如去美國吧,美國人是講英語的,我們是講漢語的,如果英語聽不懂,講不好,估計溝通就完蛋了,不能溝通,估計玩的就很難盡興了,因為有很多景點的解說你可能不 ...


解釋器模式(Interpreter):

  從名稱上來看看這個模式,個人的最初理解“解釋器”和Google的中英翻譯功能類似。如果有一天你去國外旅游去了,比如去美國吧,美國人是講英語的,我們是講漢語的,如果英語聽不懂,講不好,估計溝通就完蛋了,不能溝通,估計玩的就很難盡興了,因為有很多景點的解說你可能不明白(沒有中文翻譯的情況下,一般情況會有的)。所以我們需要一個軟體,可以把中英文互譯,那彼此就可以更好的理解對方的意思,我感覺翻譯軟體也可以稱得上是解釋器,把你不懂的解釋成你能理解的。我們寫代碼,需要編譯器把我們寫的代碼編譯成機器可以理解的機器語言,從這方面來講,C#的編譯器也是一種解釋器。

解釋器模式的角色:

   

  1)抽象解釋器(AbstractExpression):定義解釋器的介面,約定解釋器的解釋操作。其中的Interpret介面,正如其名字那樣,它是專門用來解釋該解釋器所要實現的功能。

  2)終結符表達式(TermialExpression):實現了抽象表達式角色所要求的介面,主要是一個interpret()方法;文法中的每一個終結符都有一個具體終結表達式與之相對應。比如有一個簡單的公式R=R1+R2,在裡面R1和R2就是終結符,對應的解析R1和R2的解釋器就是終結符表達式。

  3)非終結符表達式(NonterminalExpression):文法中的每一條規則都需要一個具體的非終結符表達式,非終結符表達式一般是文法中的運算符或者其他關鍵字,比如公式R=R1+R2中,“+”就是非終結符,解析“+”的解釋器就是一個非終結符表達式。

  4)環境角色(Context):這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些信息需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。

  我們演示一個判斷且或的例子。 

 1 public abstract class AbstractExpression
 2 {
 3     public abstract bool Interpret(string context);
 4 }
 5 
 6 public class TerminalExpression : AbstractExpression
 7 {
 8     private string data;
 9 
10     public TerminalExpression(string data)
11     {
12         this.data = data;
13     }
14 
15     public override bool Interpret(string context)
16     {
17         return data.Contains(context);
18     }
19 }
20 
21 public class OrExpression : AbstractExpression
22 {
23     private AbstractExpression expr1 = null;
24     private AbstractExpression expr2 = null;
25 
26     public OrExpression(AbstractExpression expr1, AbstractExpression expr2)
27     {
28         this.expr1 = expr1;
29         this.expr2 = expr2;
30     }
31 
32     public override bool Interpret(string context)
33     {
34         return expr1.Interpret(context) || expr2.Interpret(context);
35     }
36 }
37 
38 public class AndExpression : AbstractExpression
39 {
40     private AbstractExpression expr1 = null;
41     private AbstractExpression expr2 = null;
42 
43     public AndExpression(AbstractExpression expr1, AbstractExpression expr2)
44     {
45         this.expr1 = expr1;
46         this.expr2 = expr2;
47     }
48 
49     public override bool Interpret(string context)
50     {
51         return expr1.Interpret(context) || expr2.Interpret(context);
52     }
53 }
54 
55 public class Program
56 {
57     //規則:Robert 和 John 是男性
58     public static AbstractExpression GetMaleExpression()
59     {
60         AbstractExpression robert = new TerminalExpression("Robert");
61         AbstractExpression john = new TerminalExpression("John");
62         return new OrExpression(robert, john);
63     }
64 
65     //規則:Julie 是一個已婚的女性
66     public static AbstractExpression GetMarriedWomanExpression()
67     {
68         AbstractExpression julie = new TerminalExpression("Julie");
69         AbstractExpression married = new TerminalExpression("Married");
70         return new AndExpression(julie, married);
71     }
72 
73     public static void Main(string[] args)
74     {
75         AbstractExpression isMale = GetMaleExpression();
76         AbstractExpression isMarriedWoman = GetMarriedWomanExpression();
77 
78         Console.WriteLine($"John is male? {isMale.Interpret("John")}");
79         Console.WriteLine($"Julie is a married women? {isMarriedWoman.Interpret("Married Julie")}");
80     }
81 }

  這裡我們可以得出:解釋器模式有很好的擴展模式,或此時我們希望能夠找到一位男士已婚,我們只需要再寫一個非終結符表達式即可,易於擴展。我們再來看下麵這個例子。

  1 // 抽象表達式
  2 public abstract class Expression
  3 {
  4     protected Dictionary<string, int> table = new Dictionary<string, int>(9);
  5 
  6     protected Expression()
  7     {
  8         table.Add("", 1);
  9         table.Add("", 2);
 10         table.Add("", 3);
 11         table.Add("", 4);
 12         table.Add("", 5);
 13         table.Add("", 6);
 14         table.Add("", 7);
 15         table.Add("", 8);
 16         table.Add("", 9);
 17     }
 18 
 19     public virtual void Interpreter(Context context)
 20     {
 21         if (context.Statement.Length == 0)
 22         {
 23             return;
 24         }
 25 
 26         foreach (string key in table.Keys)
 27         {
 28             int value = table[key];
 29 
 30             if (context.Statement.EndsWith(key + GetPostFix()))
 31             {
 32                 context.Data += value * this.Multiplier();
 33                 context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
 34             }
 35             if (context.Statement.EndsWith(""))
 36             {
 37                 context.Statement = context.Statement.Substring(0, context.Statement.Length - 1);
 38             }
 39         }
 40     }
 41 
 42     public abstract string GetPostFix();
 43 
 44     public abstract int Multiplier();
 45 
 46     //這個可以通用,但是對於個位數字例外,所以用虛方法
 47     public virtual int GetLength()
 48     {
 49         return this.GetPostFix().Length + 1;
 50     }
 51 }
 52 
 53 //個位表達式
 54 public sealed class GeExpression : Expression
 55 {
 56     public override string GetPostFix()
 57     {
 58         return "";
 59     }
 60 
 61     public override int Multiplier()
 62     {
 63         return 1;
 64     }
 65 
 66     public override int GetLength()
 67     {
 68         return 1;
 69     }
 70 }
 71 
 72 //十位表達式
 73 public sealed class ShiExpression : Expression
 74 {
 75     public override string GetPostFix()
 76     {
 77         return "";
 78     }
 79 
 80     public override int Multiplier()
 81     {
 82         return 10;
 83     }
 84 }
 85 
 86 //百位表達式
 87 public sealed class BaiExpression : Expression
 88 {
 89     public override string GetPostFix()
 90     {
 91         return "";
 92     }
 93 
 94     public override int Multiplier()
 95     {
 96         return 100;
 97     }
 98 }
 99 
100 //千位表達式
101 public sealed class QianExpression : Expression
102 {
103     public override string GetPostFix()
104     {
105         return "";
106     }
107 
108     public override int Multiplier()
109     {
110         return 1000;
111     }
112 }
113 
114 //萬位表達式
115 public sealed class WanExpression : Expression
116 {
117     public override string GetPostFix()
118     {
119         return "";
120     }
121 
122     public override int Multiplier()
123     {
124         return 10000;
125     }
126 
127     public override void Interpreter(Context context)
128     {
129         if (context.Statement.Length == 0)
130         {
131             return;
132         }
133 
134         ArrayList tree = new ArrayList();
135 
136         tree.Add(new GeExpression());
137         tree.Add(new ShiExpression());
138         tree.Add(new BaiExpression());
139         tree.Add(new QianExpression());
140 
141         foreach (string key in table.Keys)
142         {
143             if (context.Statement.EndsWith(GetPostFix()))
144             {
145                 int temp = context.Data;
146                 context.Data = 0;
147 
148                 context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
149 
150                 foreach (Expression exp in tree)
151                 {
152                     exp.Interpreter(context);
153                 }
154                 context.Data = temp + context.Data * this.Multiplier();
155             }
156         }
157     }
158 }
159 
160 //億位表達式
161 public sealed class YiExpression : Expression
162 {
163     public override string GetPostFix()
164     {
165         return "";
166     }
167 
168     public override int Multiplier()
169     {
170         return 100000000;
171     }
172 
173     public override void Interpreter(Context context)
174     {
175         ArrayList tree = new ArrayList();
176 
177         tree.Add(new GeExpression());
178         tree.Add(new ShiExpression());
179         tree.Add(new BaiExpression());
180         tree.Add(new QianExpression());
181 
182         foreach (string key in table.Keys)
183         {
184             if (context.Statement.EndsWith(GetPostFix()))
185             {
186                 int temp = context.Data;
187                 context.Data = 0;
188                 context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
189 
190                 foreach (Expression exp in tree)
191                 {
192                     exp.Interpreter(context);
193                 }
194                 context.Data = temp + context.Data * this.Multiplier();
195             }
196         }
197     }
198 }
199 
200 //環境上下文
201 public sealed class Context
202 {
203     private string _statement;
204     private int _data;
205 
206     public Context(string statement)
207     {
208         this._statement = statement;
209     }
210 
211     public string Statement
212     {
213         get { return this._statement; }
214         set { this._statement = value; }
215     }
216 
217     public int Data
218     {
219         get { return this._data; }
220         set { this._data = value; }
221     }
222 }
223 
224 internal class Program
225 {
226     private static void Main(string[] args)
227     {
228         string roman = "五億七千三百零二萬六千四百五十二";
229         //分解:((五)億)((七千)(三百)(零)(二)萬)
230         //((六千)(四百)(五十)(二))
231 
232         Context context = new Context(roman);
233         List<Expression> tree = new List<Expression>();
234         tree.Add(new GeExpression());
235         tree.Add(new ShiExpression());
236         tree.Add(new BaiExpression());
237         tree.Add(new QianExpression());
238         tree.Add(new WanExpression());
239         tree.Add(new YiExpression());
240 
241         foreach (Expression exp in tree)
242         {
243             exp.Interpreter(context);
244         }
245 
246         Console.Write(context.Data);
247     }
248 }

  看完之後是不是想罵一句fuck,我只是想要簡單的轉換一下,卻需要寫這麼一大坨,顯然不符合我們的心意。

解釋器模式的優缺點:

  優點:

    1)易於改變和擴展文法。

    2)每一條文法規則都可以表示為一個類,因此可以方便地實現一個簡單的語言。

    3)實現文法較為容易。在抽象語法樹中每一個表達式節點類的實現方式都是相似的,這些類的代碼編寫都不會特別複雜,還可以通過一些工具自動生成節點類代碼。

    4)增加新的解釋表達式較為方便。如果用戶需要增加新的解釋表達式只需要對應增加一個新的終結符表達式或非終結符表達式類,原有表達式類代碼無須修改,符合“開閉原則”。

  缺點:

    1)對於複雜文法難以維護。在解釋器模式中,每一條規則至少需要定義一個類,因此如果一個語言包含太多文法規則,類的個數將會急劇增加,導致系統難以管理和維護,此時可以考慮使用語法分析程式等方式來取代解釋器模式。

    2)執行效率較低。由於在解釋器模式中使用了大量的迴圈和遞歸調用,因此在解釋較為複雜的句子時其速度很慢,而且代碼的調試過程也比較麻煩。

解釋器模式的應用場景:

  1)當一個語言需要解釋執行,並可以將該語言中的句子表示為一個抽象語法樹的時候,可以考慮使用解釋器模式(如XML文檔解釋、正則表達式等領域)。

  2)一些重覆出現的問題可以用一種簡單的語言來進行表達。

  3)一個語言的文法較為簡單.

  4)當執行效率不是關鍵和主要關心的問題時可考慮解釋器模式(註:高效的解釋器通常不是通過直接解釋抽象語法樹來實現的,而是需要將它們轉換成其他形式,使用解釋器模式的執行效率並不高。)

參考:https://www.cnblogs.com/PatrickLiu/p/8242238.html 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 解決Idea、WebStorm下使用Vue cli腳手架項目無法使用Webpack別名的問題 ...
  • 為什麼要用css動畫替換js動畫 導致JavaScript效率低的兩大原因:操作DOM和使用頁面動畫。 用CSS3動畫替代JS模擬動畫的好處: 不占用JS主線程; 可以利用硬體加速; 瀏覽器可對動畫做優化(元素不可見時不動畫減少對FPS影響) CSS3動畫提供了2D和3D以及常規動畫屬性介面,它可以 ...
  • 1、安裝、構建 2、項目目錄 3、antd 修改 src/App.css,在文件頂部引入 antd/dist/antd.css。 antd 目前的預設文案是英文,如果需要使用其他語言,可以參考下麵的方案。 antd 提供了一個 React 組件 ConfigProvider 用於全局配置國際化文案。 ...
  • 之前講解了什麼是微服務:微服務的核心在於服務治理,微服務架構是將複雜臃腫的單體應用進行細粒度的服務化拆分,每個拆分出來的服務各自獨立打包部署,並交由小團隊進行開發和運維,從而極大地提高了應用交付的效率。 什麼時候進行服務化拆分?拆分單體應用有哪些標準呢? 什麼時候進行服務化拆分? 比如做社交 App ...
  • 1 面向對象簡述 將 {1,3,45,56,78,90}轉化為[1,3,45,56,78,90] 1 2 方法1:面向過程 public class Student { int age = 13; String name = "wangsiyu"; public void study(){ Syst ...
  • 一、Django的內置分頁器(paginator) view index.html: 擴展 show.html model.py文件內容: 二、自定義分頁 當資料庫中數據有很多,我們通常會在前端頁面做分頁展示。 分頁的數據可以在前端頁面實現,也可以在後端實現分頁。 後端實現分頁的原理就是每次只請求一 ...
  • Tair是為瞭解決什麼問題而生? Redis很好用,相比memcached多了很多數據結構,支持持久化。但是在很長一段時間里,原生是不支持分散式的。後來就出現了很多redis集群類產品,Tair是其中勝出的優秀作品之一。 所以Tair的特性都是一些集群的特性,比如:容錯、解決單點故障、跨機房管理、多 ...
  • 前言 今天我們一起看看這個觀察者模式,這個模式簡單來說就是一個發佈訂閱類似的模式。按照名字來理解也就是存在一個觀察者和一個被觀察者。說幾個例子給大家聽,大家應該就明白了。例如在我們現在通過銀行卡支付之後,會收到銀行發過來的提示信息。例如當我們話費餘額或者流量不足之時也會收到提示信息。這其中的邏輯幫我 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...