.Net行为型设计模式之解释器模式(Interpreter)

目录
  • 一、动机(Motivate)
  • 二、意图(Intent)
  • 三、结构图(Structure)
  • 四、模式的组成
  • 五、解释器模式的代码实现
  • 六、解释器模式的实现要点:
    • 1、解释器模式的主要优点有:
    • 2、解释器模式的主要缺点有:
    • 3、在下面的情况下可以考虑使用解释器模式:
  • 七、.NET 解释器模式的实现
  • 八、总结

一、动机(Motivate)

在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。

二、意图(Intent)

给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。                                 ——《设计模式》GoF

三、结构图(Structure)

四、模式的组成

可以看出,在解释器模式的结构图有以下角色:
(1)、抽象表达式(AbstractExpression):定义解释器的接口,约定解释器的解释操作。其中的Interpret接口,正如其名字那样,它是专门用来解释该解释器所要实现的功能。
(2)、终结符表达式(Terminal Expression):实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
(3)、非终结符表达式(Nonterminal Expression):文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。
(4)、环境角色(Context):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。
(5)、客户端(Client):指的是使用解释器的客户端,通常在这里将按照语言的语法做的表达式转换成使用解释器对象描述的抽象语法树,然后调用解释操作。

五、解释器模式的代码实现

在很多场合都需要把数字转换成中文,我们就可以使用解释器来实现该功能,把给定的数字解释成符合语法规范的汉字表示法。实现代码如下:

static void Main(string[] args)
{
    string roman = "五亿七千三百零二万六千四百五十二";
    //分解:((五)亿)((七千)(三百)(零)(二)万)
    //((六千)(四百)(五十)(二))

    Context context = new Context(roman);
    ArrayList tree = new ArrayList();

    tree.Add(new GeExpression());
    tree.Add(new ShiExpression());
    tree.Add(new BaiExpression());
    tree.Add(new QianExpression());
    tree.Add(new WanExpression());
    tree.Add(new YiExpression());

    foreach (Expression exp in tree)
    {
        exp.Interpreter(context);
    }

    Console.Write(context.Data);
}
// 抽象表达式
public abstract class Expression
{
    protected Dictionary<string, int> table = new Dictionary<string, int>(9);

    protected Expression()
    {
        table.Add("一", 1);
        table.Add("二", 2);
        table.Add("三", 3);
        table.Add("四", 4);
        table.Add("五", 5);
        table.Add("六", 6);
        table.Add("七", 7);
        table.Add("八", 8);
        table.Add("九", 9);
    }

    public virtual void Interpreter(Context context)
    {
        if (context.Statement.Length == 0)
        {
            return;
        }

        foreach (string key in table.Keys)
        {
            int value = table[key];

            if (context.Statement.EndsWith(key + GetPostFix()))
            {
                context.Data += value * this.Multiplier();
                context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
            }
            if (context.Statement.EndsWith("零"))
            {
                context.Statement = context.Statement.Substring(0, context.Statement.Length - 1);
            }
        }
    }

    public abstract string GetPostFix();

    public abstract int Multiplier();

    //这个可以通用,但是对于个位数字例外,所以用虚方法
    public virtual int GetLength()
    {
        return this.GetPostFix().Length + 1;
    }
}

//个位表达式
public sealed class GeExpression : Expression
{
    public override string GetPostFix()
    {
        return "";
    }

    public override int Multiplier()
    {
        return 1;
    }

    public override int GetLength()
    {
        return 1;
    }
}

//十位表达式
public sealed class ShiExpression : Expression
{
    public override string GetPostFix()
    {
        return "十";
    }

    public override int Multiplier()
    {
        return 10;
    }
}

//百位表达式
public sealed class BaiExpression : Expression
{
    public override string GetPostFix()
    {
        return "百";
    }

    public override int Multiplier()
    {
        return 100;
    }
}

//千位表达式
public sealed class QianExpression : Expression
{
    public override string GetPostFix()
    {
        return "千";
    }

    public override int Multiplier()
    {
        return 1000;
    }
}

//万位表达式
public sealed class WanExpression : Expression
{
    public override string GetPostFix()
    {
        return "万";
    }

    public override int Multiplier()
    {
        return 10000;
    }

    public override void Interpreter(Context context)
    {
        if (context.Statement.Length == 0)
        {
            return;
        }

        ArrayList tree = new ArrayList();

        tree.Add(new GeExpression());
        tree.Add(new ShiExpression());
        tree.Add(new BaiExpression());
        tree.Add(new QianExpression());

        foreach (string key in table.Keys)
        {
            if (context.Statement.EndsWith(GetPostFix()))
            {
                int temp = context.Data;
                context.Data = 0;

                context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());

                foreach (Expression exp in tree)
                {
                    exp.Interpreter(context);
                }
                context.Data = temp + context.Data * this.Multiplier();
            }
        }
    }
}

//亿位表达式
public sealed class YiExpression : Expression
{
    public override string GetPostFix()
    {
        return "亿";
    }

    public override int Multiplier()
    {
        return 100000000;
    }

    public override void Interpreter(Context context)
    {
        ArrayList tree = new ArrayList();

        tree.Add(new GeExpression());
        tree.Add(new ShiExpression());
        tree.Add(new BaiExpression());
        tree.Add(new QianExpression());

        foreach (string key in table.Keys)
        {
            if (context.Statement.EndsWith(GetPostFix()))
            {
                int temp = context.Data;
                context.Data = 0;
                context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());

                foreach (Expression exp in tree)
                {
                    exp.Interpreter(context);
                }
                context.Data = temp + context.Data * this.Multiplier();
            }
        }
    }
}

//环境上下文
public sealed class Context
{
    private string _statement;
    private int _data;

    public Context(string statement)
    {
        this._statement = statement;
    }

    public string Statement
    {
        get { return this._statement; }
        set { this._statement = value; }
    }

    public int Data
    {
        get { return this._data; }
        set { this._data = value; }
    }
}

六、解释器模式的实现要点:

使用Interpreter模式来表示文法规则,从而可以使用面向对象技巧方便地“扩展”文法。
Interpreter模式比较适合简单的文法表示,对于复杂的文法表示,Interpreter模式会产生比较大的类层次结构,需要求助于语法分析生成器这样的标准工具。

1、解释器模式的主要优点有:

1】、易于改变和扩展文法。
2】、每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。
3】、实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。
4】、增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”

2、解释器模式的主要缺点有:

1】、对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
2】、执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

3、在下面的情况下可以考虑使用解释器模式:

Interpreter模式的应用场合是Interpreter模式应用中的难点,只有满足“业务规则频繁变化,且类似的模式不断重复出现,并且容易抽象为语法规则的问题”才适合使用Interpreter模式。
1】、当一个语言需要解释执行,并可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式(如XML文档解释、正则表达式等领域)
2】、一些重复出现的问题可以用一种简单的语言来进行表达。
3】、一个语言的文法较为简单.
4】、当执行效率不是关键和主要关心的问题时可考虑解释器模式(注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。)

七、.NET 解释器模式的实现

正则表达式就是一个典型的解释器。ASP.NET中,把aspx文件转化为dll时,会对html语言进行处理,这个处理过程也包含了解释器的模式在里面。Interpreter模式其实有Composite模式的影子,但它们解决的问题是不一样的。

八、总结

(1)解释器和组合模式:这两种可以组合使用,一般非终结符解释器相当于组合模式中的组合对象,终结符解释器相当于叶子对象。
(2)解释器模式和迭代器模式:由于解释器模式通常使用组合模式来实现,因此在遍历整个对象结构时,可以使用迭代器模式。
(3)解释器模式和享元模式:在使用解释器模式的时候,可能会造成多个细粒度对象,如各式各样的终结符解释器,而这些终结符解释器对不同的表达式来说是一样的,是可以共用的,因此可以引入享元模式来共享这些对象。
(4)解释器模式和访问者模式:在解释器模式中,语法规则和解释器对象是有对应关系的。语法规则的变动意味着功能的变化。自然会导致使用不同的解释器对象;而且一个语法规由可以被不同的解释器解释执行。因此在构建抽象语法树的时候,如果每个节点所对应的解释器对象是固定的,这意味着该节点对应的功能是固定的,那么就不得不根据需要来构建不同的抽象语法树。为了让构建的抽象语法树较为通用,那就要求解释器的功能不要那么固定,要能很方便地改变解释器的功能,这个时候就变成了如何能够很方便地更改树形结构中节点对象的功能了,访问者模式可以很好的实现这个功能。

到此这篇关于.Net行为型设计模式之解释器模式(Interpreter)的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • .Net行为型设计模式之命令模式(Command)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.命令模式的代码实现 六.命令模式的实现要点: 1.命令模式的优点: 2.命令模式的缺点: 3.命令模式的使用场景: 七..NET 中命令模式的实现 一.动机(Motivate) 在我们的现实生活中有很多例子可以拿来说明这个模式,我们还拿吃饺子这个事情来说.我的奶奶说了,今天想吃饺子,发出了命令,然后我奶奶就去看电视去了.我们夫妻俩收到命令就开始和面,做饺子馅,包饺子.饺子包好了,我

  • .Net行为型设计模式之迭代器模式(Iterator)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图 四.模式的组成 五.迭代器模式的代码实现 六.迭代器模式的实现要点: 迭代器模式的优点: 迭代器模式的缺点: 迭代器模式的使用场景: 七..NET 中迭代器模式的实现 一.动机(Motivate) 在软件构建过程中,集合对象内部结构常常变化各异.但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素:同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能.使用面向

  • .Net行为型设计模式之状态模式(State)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.状态模式的代码实现 六.状态模式的实现要点: 1.状态模式的优点 2.状态模式的缺点 3.在以下情况下可以使用状态模式: 七..NET 状态模式的实现 一.动机(Motivate) 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同.如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操

  • .Net行为型设计模式之备忘录模式(Memento)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.备忘录模式的代码实现 六.备忘录模式的实现要点: 1.备忘录模式的主要优点有: 2.备忘录模式的主要缺点有: 3.在下面的情况下可以考虑使用备忘录模式: 4.备忘录的封装性 5.多备份实现 6.Memento模式与Command模式的异同 七..NET 备忘录模式的实现 一.动机(Motivate) 我们看上图,一个对象肯定会有很多状态,这些状态肯定会相互转变而促进对象的发展,如果

  • .Net行为型设计模式之访问者模式(Visitor)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.访问者模式的代码实现 六.访问者模式的实现要点: (1).访问者模式的主要优点有: (2).访问者模式的主要缺点有: (3).在下面的情况下可以考虑使用访问者模式: 七..NET 访问者模式的实现 一.动机(Motivate) 在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设

  • .Net行为型设计模式之模板方法模式(Template Method)

    一.动机(Motivate) “模板方法”,就是有一个方法包含了一个模板,这个模板是一个算法.在我们的现实生活中有很多例子可以拿来说明这个模式,就拿吃饺子这个事情来说,要想吃到饺子必须经过三步,第一步是“和面”,第二步是“包馅”,第三步是“煮饺子”,这三步就是一个算法,我们要想吃到不同的面和馅的饺子,对这三步中的任意一步就行操作就可以,也可以完全定义这三步 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)

  • .Net行为型设计模式之观察者模式(Observer)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图 四.模式的组成 五.观察者模式的代码实现 六.观察者模式的实现要点: 1.观察者模式的优点: 2.观察者模式的缺点: 七..NET 中观察者模式的实现 一.动机(Motivate) “观察者模式”在现实生活中,实例其实是很多的,比如:八九十年代我们订阅的报纸,我们会定期收到报纸,因为我们订阅了.银行可以给储户发手机短信,也是“观察者模式”很好的使用的例子,因为我们订阅了银行的短信业务,当我们账户余额发生变化就会收到通知等.

  • .Net行为型设计模式之职责链模式(Chain of Responsibility)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.职责链模式的代码实现 六.职责链模式的实现要点: 1.职责链模式的主要优点有: 2.职责链模式的主要缺点有: 3.在下面的情况下可以考虑使用职责链模式: 七..NET 职责链模式的实现 一.动机(Motivate) 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合.如何使请求的发送者不需要指

  • .Net行为型设计模式之策略模式(Stragety)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.策略模式的代码实现 六.策略模式的实现要点: 1.策略模式的主要优点有: 2.策略模式的主要缺点有: 3.在下面的情况下可以考虑使用策略模式: 七..NET 策略模式的实现 一.动机(Motivate) 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂:而且有时候支持不使用的算法也是一个性能负担.如何在运行时根据需要透

  • .Net行为型设计模式之中介者模式(Mediator)

    目录 一.动机(Motivate) 二.意图(Intent) 三.结构图(Structure) 四.模式的组成 五.中介者模式的代码实现 六.中介者模式的实现要点: 1.中介者模式的优点 2.中介者模式的缺点 七..NET 中介者模式的实现 一.动机(Motivate) 为什么要使用中介者模式呢?如果不使用中介者模式的话,各个同事对象将会相互进行引用,如果每个对象都与多个对象进行交互时,将会形成如下图所示的网状结构. 从上图可以发现,如果不使用中介者模式的话,每个对象之间过度耦合,这样的既不利于

随机推荐