解釋器模式(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 =https://www.cnblogs.com/az4215/p/ data;13 }14 15 public override bool Interpret(string context)16 {17 return data.Contains(context);18 }19 }20 21 public class OrExpression : AbstractExpression22 {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 : AbstractExpression39 {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 Program56 {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 =https://www.cnblogs.com/az4215/p/ 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 : Expression102 {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 : Expression116 {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 = https://www.cnblogs.com/az4215/p/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 = https://www.cnblogs.com/az4215/p/temp + context.Data * this.Multiplier();155 }156 }157 }158 }159 160 //億位運算式161 public sealed class YiExpression : Expression162 {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 = https://www.cnblogs.com/az4215/p/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 = https://www.cnblogs.com/az4215/p/temp + context.Data * this.Multiplier();195 }196 }197 }198 }199 200 //環境背景關系201 public sealed class Context202 {203 private string _statement;204 private int _data;205 206 public Context(string statement)207 {208 this._statement = statement;209 }210 211 public string Statement212 {213 get { return this._statement; }214 set { this._statement = value; }215 }216 217 public int Data218 {219 get { return this._data; }220 set { this._data =https://www.cnblogs.com/az4215/p/ value; }221 }222 }223 224 internal class Program225 {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
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/39944.html
標籤:設計模式
上一篇:設計模式-行為型-備忘錄模式
