3-11设计模式之解释器模式(Interpreter)

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 小结:

解释器模式在实际开发中相对于其他模式使用较少,因此笔者放在设计模式全家桶的最后一节来进行说明,大家简单了解下就好。


更多设计模式详见:设计模式全家桶

发表评论