zoukankan      html  css  js  c++  java
  • 设计模式学习总结解释器模式(Interpreter Method)

    问题:
    在面向对象的设计中和开发中,经常会遇到,有一些请求或操作,很难用对象的形式来表示或者处理,比如我们写一个简单的算术计算工具计算“a+b”,可以简单的定义一个方法,接收两个变量,做算术“+”计算返回结果,可是如果让这个方法可以实现“加减乘除”四则运算,我们又要修改方法加入一个运算符参数,但是由于需求变化,又要加入多个操作数的运算如:“a+b-c*d”,该如何处理呢?穷举方法定义所有可能出现的操作显然是不可能的,我们能否定义一种来解析算术表达式的方法,直接将算术表达式作为字符串传递给计算方法,计算方法将算术表达式解析后再计算返回结果?
    定义:
    Interpreter模式是一种行为模式,给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

    意图:
    将某一特定领域的比较复杂问题,表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,来应对使用普通的编程方式实现面临非常的频繁变化的问题。(建立语法树,然后用语法将表达式进行解析。)

    参与者:
    •抽象表达式(Abstract Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个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来充当环境角色就足够了。

     UML:


    代码说明:

    一个解析算术表达式计算的例子,为了快速说明问题,例子仅支持双操作数运算

    /// <summary>
    /// 抽象表达式(Abstract Expression)角色
    /// </summary>
    public abstract class  Expression
    {
            public abstract void Interpret();
    }

    /// <summary>
    /// 具体的算术解析器表达式
    /// </summary>
    public class CalculatorExpression : Expression
    {
        public int Value;
            string Expression;
        public CalculatorExpression(string _expression)
        {
            Expression = _expression;
        }
        public override void Interpret()
        {
            string[] Numbers = Expression.Split('+','-');
             
            if (Expression.IndexOf('+')>-1)
            {
                this.Value = int.Parse(Numbers[0]) + int.Parse(Numbers[1]);
            }
            else if (Expression.IndexOf('-') > -1)
            {
                this.Value = int.Parse(Numbers[0]) - int.Parse(Numbers[1]);
            }
            else if (Expression.IndexOf('*') > -1)
            {
                this.Value = int.Parse(Numbers[0]) * int.Parse(Numbers[1]);
            }
            else if (Expression.IndexOf('/') > -1)
            {
                this.Value = int.Parse(Numbers[0]) / int.Parse(Numbers[1]);
            }
        }
    }
    /// <summary>
    /// 环境(Context)角色
    /// </summary>
    public class ContextCalculator 
    {
        /// <summary>
        
    /// 计算方法
        
    /// </summary>
        
    /// <param name="expression"></param>
        
    /// <returns></returns>
        public int Calculate(string expression)
        {
            CalculatorExpression ex = new CalculatorExpression(expression);
            ex.Interpret();
            return ex.Value;
        }
    }
    public void InterpreterTest()
    {
        ContextCalculator c = new ContextCalculator();
        //传入表达式计算
        
    //无论是扩展为多操作数,还是加入括号,客户端都不会受到影响。
        c.Calculate("2+1");
    }

    优点:
    •可以很容易地改变和扩展文法,因为该模式使用类表示文法规则,你可使用继承来改变或扩展文法,实现灵活的扩展。
    •容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。
    缺点:
    •文法中的每一条规则至少定义了一个类,对于复杂的文法表示会产生比较大的类层次结构,难以管理和维护。
    •因为文句会分析成树结构,解释器需要递归访问它,所以效率会受影响。

     应用场景:
    如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

    PS:.Net系统中提供了很多解释器,如:LINQ,正则表达式等等。

  • 相关阅读:
    大话数据结构—散列表查找(哈希表)
    全栈project师?给把瑞士军刀你去砍鬼子好不好!?
    合作开发带来的思考
    女码农献丑-企业智能机器人客服(图灵机器人)
    Elasticsearch聚合 之 Date Histogram聚合
    Elasticsearch聚合 之 Terms
    Elasticsearch聚合初探——metric篇
    AngularJS API之$injector ---- 依赖注入
    AngularJS API之extend扩展对象
    AngularJS API之equal比较对象
  • 原文地址:https://www.cnblogs.com/ejiyuan/p/2617203.html
Copyright © 2011-2022 走看看