1. 程式人生 > >C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】

C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】

要求 ict string 技術 get protect dict site 關鍵字

原文:C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】

一、引言

今天我們開始講“行為型”設計模式的第十一個模式,也是面向對象設計模式的最後一個模式,先要說明一下,其實這個模式不是最後一個模式(按Gof的排序來講),為什麽把它放在最後呢?因為我們在業務系統中寫一個解釋器的機會並不是很多,實踐比較少,理解和應用該模式就有些困難,所以就放在最後來說。該模式就是【解釋器模式】,英文名稱是:Interpreter Pattern。按老規矩,先從名稱上來看看這個模式,個人的最初理解“解釋器”和Google的中英翻譯功能類似。如果有一天你去國外旅遊去了,比如去美國吧,美國人是講英語的,我們是講漢語的,如果英語聽不懂,講不好,估計溝通就完蛋了,不能溝通,估計玩的就很難盡興了,因為有很多景點的解說你可能不明白(沒有中文翻譯的情況下,一般情況會有的)。所以我們需要一個軟件,可以把中英文互譯,那彼此就可以更好的理解對方的意思,我感覺翻譯軟件也可以稱得上是解釋器,把你不懂的解釋成你能理解的。我們寫代碼,需要編譯器把我們寫的代碼編譯成機器可以理解的機器語言,從這方面來講,C#的編譯器也是一種解釋器。

二、解釋器模式的詳細介紹



2.1、動機(Motivate)

在軟件構建過程中,如果某一特定領域的問題比較復雜,類似的模式不斷重復出現,如果使用普通的編程方式來實現將面臨非常頻繁的變化。在這種情況下,將特定領域的問題表達為某種語法規則下的句子,然後構建一個解釋器來解釋這樣的句子,從而達到解決問題的目的。

2.2、意圖(Intent)

給定一個語言,定義它的文法的一種表示,並定義一種解釋器,這個解釋器使用該表示來解釋語言中的句子。       ——《設計模式》GoF

2.3、結構圖(Structure)

技術分享圖片

2.4、模式的組成

可以看出,在解釋器模式的結構圖有以下角色:

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

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

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

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

(5)、客戶端(Client):指的是使用解釋器的客戶端,通常在這裏將按照語言的語法做的表達式轉換成使用解釋器對象描述的抽象語法樹,然後調用解釋操作。

2.5、解釋器模式的代碼實現

在很多場合都需要把數字轉換成中文,我們就可以使用解釋器來實現該功能,把給定的數字解釋成符合語法規範的漢字表示法。實現代碼如下:

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


三、解釋器模式的實現要點:

使用Interpreter模式來表示文法規則,從而可以使用面向對象技巧方便地“擴展”文法。

  Interpreter模式比較適合簡單的文法表示,對於復雜的文法表示,Interpreter模式會產生比較大的類層次結構,需要求助於語法分析生成器這樣的標準工具。

(1)、解釋器模式的主要優點有:

1】、易於改變和擴展文法。

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

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

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

 (2)、解釋器模式的主要缺點有:

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

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

(3)、在下面的情況下可以考慮使用解釋器模式:

Interpreter模式的應用場合是Interpreter模式應用中的難點,只有滿足“業務規則頻繁變化,且類似的模式不斷重復出現,並且容易抽象為語法規則的問題”才適合使用Interpreter模式。

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

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

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

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


四、.NET 解釋器模式的實現

正則表達式就是一個典型的解釋器。ASP.NET中,把aspx文件轉化為dll時,會對html語言進行處理,這個處理過程也包含了解釋器的模式在裏面。Interpreter模式其實有Composite模式的影子,但它們解決的問題是不一樣的。

五、總結

今天就寫到這裏了,23種設計模式都寫完了,有時間了,再寫一篇文章,為這個系列做一個總結,同時也做一個設計模式的目錄,方便大家瀏覽和學習。解釋器模式可以和其他模式混合使用,具體的使用方法和解決的問題我列出了一個表,大家好好了解一下,或許對大家有些幫助。列表如下:

(1)解釋器和組合模式

這兩種可以組合使用,一般非終結符解釋器相當於組合模式中的組合對象,終結符解釋器相當於葉子對象。

(2)解釋器模式和叠代器模式

由於解釋器模式通常使用組合模式來實現,因此在遍歷整個對象結構時,可以使用叠代器模式。

(3)解釋器模式和享元模式

在使用解釋器模式的時候,可能會造成多個細粒度對象,如各式各樣的終結符解釋器,而這些終結符解釋器對不同的表達式來說是一樣的,是可以共用的,因此可以引入享元模式來共享這些對象。

(4)解釋器模式和訪問者模式

在解釋器模式中,語法規則和解釋器對象是有對應關系的。語法規則的變動意味著功能的變化。自然會導致使用不同的解釋器對象;而且一個語法規由可以被不同的解釋器解釋執行。因此在構建抽象語法樹的時候,如果每個節點所對應的解釋器對象是固定的,這意味著該節點對應的功能是固定的,那麽就不得不根據需要來構建不同的抽象語法樹。為了讓構建的抽象語法樹較為通用,那就要求解釋器的功能不要那麽固定,要能很方便地改變解釋器的功能,這個時候就變成了如何能夠很方便地更改樹形結構中節點對象的功能了,訪問者模式可以很好的實現這個功能。

C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】