3.11.1 模式意圖:
在系統(tǒng)會有一些需要進行轉(zhuǎn)換的字符或句子,通常會使用正則表達式,但正則表達式使用起來相對復雜,如果我們需要轉(zhuǎn)換的句子較少、簡單,可以使用解釋器模式來完成轉(zhuǎn)換的需求。
3.11.2 模式概念:
它屬于行為型模式, 給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
【補充】在解釋器模式示例之前,先介紹幾個概念:
文法:要描述一種語言時,需要給出這種語言的所有句子,當句子的數(shù)目是有限可數(shù)時,就要都列出來;當句子是一個無窮集,也就是無限不可數(shù)時,就要給出可以表示它們的結(jié)構(gòu)的描述方法或者說,句子的組成規(guī)則。這種規(guī)則就是文法。
抽象表達式(AbstractExpression):定義解釋器的接口,約定解釋器的解釋操作。其中的Interpret接口,正如其名字那樣,它是專門用來解釋該解釋器所要實現(xiàn)的功能。
終結(jié)符表達式(Terminal Expression):實現(xiàn)了抽象表達式角色所要求的接口,主要是一個Interpret()方法;文法中的每一個終結(jié)符都有一個具體終結(jié)表達式與之相對應。例如R=R1+R2,其中R1和R2就是終結(jié)符,對應的解析R1和R2的解釋器就是終結(jié)符表達式。
非終結(jié)符表達式(Nonterminal Expression):文法中的每一條規(guī)則都需要一個具體的非終結(jié)符表達式,非終結(jié)符表達式一般是文法中的運算符或者其他關(guān)鍵字,比如公式R=R1+R2中,“+”就是非終結(jié)符,解析“+”的解釋器就是一個非終結(jié)符表達式。
環(huán)境角色(Context):這個角色的任務(wù)一般是用來存放文法中各個終結(jié)符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些信息需要存放到環(huán)境角色中,很多情況下我們使用Map來充當環(huán)境角色就足夠了。
3.11.3 模式元素:
- 抽象表達式(AbstractExpression)
- 終結(jié)符表達式(Terminal Expression)
- 非終結(jié)符表達式(Nonterminal Expression)
- 環(huán)境角色(Context)
3.11.4 代碼示例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Custom.Log;
using System.Linq;
namespace InterpreterPattern
{
public class Context
{
private string text;
public string Input
{
set { text= value; }
}
public string Output
{
get { return text; }
}
}
public abstract class AbstractExpression
{
public abstract void Interpret(Context context);
}
public class NumberToChineseExpression : AbstractExpression
{
private static Dictionary<string, string> _Dictionary = new Dictionary<string, string>();
static NumberToChineseExpression()
{
_Dictionary.Add("0", "零");
_Dictionary.Add("1", "一");
_Dictionary.Add("2", "二");
_Dictionary.Add("3", "三");
_Dictionary.Add("4", "四");
_Dictionary.Add("5", "五");
_Dictionary.Add("6", "六");
_Dictionary.Add("7", "七");
_Dictionary.Add("8", "八");
_Dictionary.Add("9", "九");
}
public override void Interpret(Context context)
{
string text = context.Output;
if (string.IsNullOrEmpty(text))
return;
List<string> numberList = new List<string>();
foreach (var item in text)
{
if (_Dictionary.ContainsKey(item.ToString()))
{
numberList.Add(_Dictionary[item.ToString()]);
}
else
{
numberList.Add(item.ToString());
}
}
this.Log($"轉(zhuǎn)換后:{string.Concat(numberList)}");
context.Input=string.Concat(numberList);
}
}
public class ChineseToEnglishExpression : AbstractExpression
{
private static Dictionary<string, string> _Dictionary = new Dictionary<string, string>();
static ChineseToEnglishExpression()
{
_Dictionary.Add( "零","Zero");
_Dictionary.Add( "一","One");
_Dictionary.Add( "二","Two");
_Dictionary.Add( "三","Three");
_Dictionary.Add( "四","Four");
_Dictionary.Add( "五","Five");
_Dictionary.Add( "六","Six");
_Dictionary.Add( "七","Seven");
_Dictionary.Add( "八", "Eight");
_Dictionary.Add( "九","Nine");
}
public override void Interpret(Context context)
{
string text = context.Output;
if (string.IsNullOrEmpty(text))
return;
List<string> numberList = new List<string>();
foreach (var item in text)
{
if (_Dictionary.ContainsKey(item.ToString()))
{
numberList.Add(_Dictionary[item.ToString()]);
}
else
{
numberList.Add(item.ToString());
}
}
this.Log($"轉(zhuǎn)換后:{string.Concat(numberList)}");
context.Input = string.Concat(numberList);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Custom.Log;
namespace InterpreterPattern
{
public class InterpreterComponent : MonoBehaviour
{
void Start()
{
Context context = new Context();
context.Input = "123456789";
IList<AbstractExpression> list = new List<AbstractExpression>();
list.Add(new NumberToChineseExpression());
list.Add(new ChineseToEnglishExpression());
foreach (AbstractExpression exp in list)
{
exp.Interpret(context);
}
this.Log($"最終輸出:{context.Output}");
}
}
}
3.11.5 寫法對比:
略
3.11.6 模式分析:
解釋器模式使用起來相對簡單,擴展性也比較靈活。但對于文法的維護以及遞歸調(diào)用產(chǎn)生的耗時問題,使它在場景中應用較少。
3.11.7 應用場景:
可以用簡單文法來轉(zhuǎn)換的句子或指令。
3.11.8 小結(jié):
解釋器模式在實際開發(fā)中相對于其他模式使用較少,因此筆者放在設(shè)計模式全家桶的最后一節(jié)來進行說明,大家簡單了解下就好。