3.11設(shè)計模式之解釋器模式(Interpreter)

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é)來進行說明,大家簡單了解下就好。


更多設(shè)計模式詳見:設(shè)計模式全家桶

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。