设计模式之Interpreter解释器模式

来源:互联网 发布:c语言实现ftp文件传输 编辑:程序博客网 时间:2024/05/01 07:51
 

意图intent给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

适用性:

  • 当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:
  • 该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。
  • 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。

 

DefinitionGiven a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

 

participants

    The classes and/or objects participating in this pattern are:

  • AbstractExpression  (Expression)
    • declares an interface for executing an operation
  • TerminalExpression  ( ThousandExpression, HundredExpression, TenExpression, OneExpression )
    • implements an Interpret operation associated with terminal symbols in the grammar.
    • an instance is required for every terminal symbol in the sentence.
  • NonterminalExpression  ( not used )
    • one such class is required for every rule R ::= R1R2...Rn in the grammar
    • maintains instance variables of type AbstractExpression for each of the symbols R1 through Rn.
    • implements an Interpret operation for nonterminal symbols in the grammar. Interpret typically calls itself recursively on the variables representing R1 through Rn.
  • Context  (Context)
    • contains information that is global to the interpreter
  • Client  (InterpreterApp)
    • builds (or is given) an abstract syntax tree representing a particular sentence in the language that the grammar defines. The abstract syntax tree is assembled from instances of the NonterminalExpression and TerminalExpression classes
    • invokes the Interpret operation

Interpreter模式其实也是非常简单的,主要就是用了一个interface,然后client利用interface可以通过具体的class来进行操作,从而得到具体、实际的结果。TerminalExpressionNonTerminalExpression都实现了AbstractionExpressioninterpret函数。在下面的real world代码中没有用到NonTerminalExpression这个类,实际上是一样的,主要就是实现了那个interpret类。Over

sample code in C#

This structural code demonstrates the Interpreter patterns, which using a defined grammer, provides the interpreter that processes parsed statements.

// Interpreter pattern -- Structural example

 

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Interpreter.Structural
{
  
  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      Context context = new Context();

      // Usually a tree
      ArrayList list = new ArrayList();

      // Populate 'abstract syntax tree'
      list.Add(new TerminalExpression());
      list.Add(new NonterminalExpression());
      list.Add(new TerminalExpression());
      list.Add(new TerminalExpression());

      // Interpret
      foreach (AbstractExpression exp in list)
      {
        exp.Interpret(context);
      }

      // Wait for user
      Console.Read();
    }
  }

  // "Context"

  class Context
  {
  }

  // "AbstractExpression"

  abstract class AbstractExpression
  {
    public abstract void Interpret(Context context);
  }

  // "TerminalExpression"

  class TerminalExpression : AbstractExpression
  {
    public override void Interpret(Context context)  
    {
      Console.WriteLine("Called Terminal.Interpret()");
    }
  }

  // "NonterminalExpression"

  class NonterminalExpression : AbstractExpression
  {
    public override void Interpret(Context context)  
    {
      Console.WriteLine("Called Nonterminal.Interpret()");
    }  
  }
}

 

Output Called

Terminal.Interpret()

Called Nonterminal.Interpret()

Called Terminal.Interpret()

Called Terminal.Interpret()

 

This real-world code demonstrates the Interpreter pattern which is used to convert a Roman numeral to a decimal.

// Interpreter pattern -- Real World example

 

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Interpreter.RealWorld
{

  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      string roman = "MCMXXVIII";
      Context context = new Context(roman);

      // Build the 'parse tree'
      ArrayList tree = new ArrayList();
      tree.Add(new ThousandExpression());
      tree.Add(new HundredExpression());
      tree.Add(new TenExpression());
      tree.Add(new OneExpression());

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

      Console.WriteLine("{0} = {1}",
        roman, context.Output);

      // Wait for user
      Console.Read();
    }
  }

  // "Context"

  class Context
  {
    private string input;
    private int output;

    // Constructor
    public Context(string input)
    {
      this.input = input;
    }

    // Properties
    public string Input
    {
      get{ return input; }
      set{ input = value; }
    }

    public int Output
    {
      get{ return output; }
      set{ output = value; }
    }
  }

  // "AbstractExpression"

  abstract class Expression
  {
    public void Interpret(Context context)
    {
      if (context.Input.Length == 0)
        return;

      if (context.Input.StartsWith(Nine()))
      {
        context.Output += (9 * Multiplier());
        context.Input = context.Input.Substring(2);
      }
      else if (context.Input.StartsWith(Four()))
      {
        context.Output += (4 * Multiplier());
        context.Input = context.Input.Substring(2);
      }
      else if (context.Input.StartsWith(Five()))
      {
        context.Output += (5 * Multiplier());
        context.Input = context.Input.Substring(1);
      }

      while (context.Input.StartsWith(One()))
      {
        context.Output += (1 * Multiplier());
        context.Input = context.Input.Substring(1);
      }
    }

    public abstract string One();
    public abstract string Four();
    public abstract string Five();
    public abstract string Nine();
    public abstract int Multiplier();
  }

  // Thousand checks for the Roman Numeral M
  // "TerminalExpression"

  class ThousandExpression : Expression
  {
    public override string One() { return "M"; }
    public override string Four(){ return " "; }
    public override string Five(){ return " "; }
    public override string Nine(){ return " "; }
    public override int Multiplier() { return 1000; }
  }

  // Hundred checks C, CD, D or CM
  // "TerminalExpression"

  class HundredExpression : Expression
  {
    public override string One() { return "C"; }
    public override string Four(){ return "CD"; }
    public override string Five(){ return "D"; }
    public override string Nine(){ return "CM"; }
    public override int Multiplier() { return 100; }
  }

  // Ten checks for X, XL, L and XC
  // "TerminalExpression"

  class TenExpression : Expression
  {
    public override string One() { return "X"; }
    public override string Four(){ return "XL"; }
    public override string Five(){ return "L"; }
    public override string Nine(){ return "XC"; }
    public override int Multiplier() { return 10; }
  }

  // One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
  // "TerminalExpression"

  class OneExpression : Expression
  {
    public override string One() { return "I"; }
    public override string Four(){ return "IV"; }
    public override string Five(){ return "V"; }
    public override string Nine(){ return "IX"; }
    public override int Multiplier() { return 1; }
  }
}

 

Output

MCMXXVIII = 1928