3.11.1 模式意图:
在系统会有一些需要进行转换的字符或句子,通常会使用正则表达式,但正则表达式使用起来相对复杂,如果我们需要转换的句子较少、简单,可以使用解释器模式来完成转换的需求。
3.11.2 模式概念:
它属于行为型模式, 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
【补充】在解释器模式示例之前,先介绍几个概念:
-
文法:要描述一种语言时,需要给出这种语言的所有句子,当句子的数目是有限可数时,就要都列出来;当句子是一个无穷集,也就是无限不可数时,就要给出可以表示它们的结构的描述方法或者说,句子的组成规则。这种规则就是文法。
-
抽象表达式(AbstractExpression):定义解释器的接口,约定解释器的解释操作。其中的Interpret接口,正如其名字那样,它是专门用来解释该解释器所要实现的功能。
-
终结符表达式(Terminal Expression):实现了抽象表达式角色所要求的接口,主要是一个Interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。例如R=R1+R2,其中R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
-
非终结符表达式(Nonterminal Expression):文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。
-
环境角色(Context):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。
3.11.3 模式元素:
- 抽象表达式(AbstractExpression)
- 终结符表达式(Terminal Expression)
- 非终结符表达式(Nonterminal Expression)
- 环境角色(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 _Dictionary = new Dictionary();
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 numberList = new List();
foreach (var item in text)
{
if (_Dictionary.ContainsKey(item.ToString()))
{
numberList.Add(_Dictionary[item.ToString()]);
}
else
{
numberList.Add(item.ToString());
}
}
this.Log($"转换后:{string.Concat(numberList)}");
context.Input=string.Concat(numberList);
}
}
public class ChineseToEnglishExpression : AbstractExpression
{
private static Dictionary _Dictionary = new Dictionary();
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 numberList = new List();
foreach (var item in text)
{
if (_Dictionary.ContainsKey(item.ToString()))
{
numberList.Add(_Dictionary[item.ToString()]);
}
else
{
numberList.Add(item.ToString());
}
}
this.Log($"转换后:{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 list = new List();
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 模式分析:
解释器模式使用起来相对简单,扩展性也比较灵活。但对于文法的维护以及递归调用产生的耗时问题,使它在场景中应用较少。
3.11.7 应用场景:
可以用简单文法来转换的句子或指令。
3.11.8 小结:
解释器模式在实际开发中相对于其他模式使用较少,因此笔者放在设计模式全家桶的最后一节来进行说明,大家简单了解下就好。