设计模式学习笔记--Interpeter解释模式

本文介绍了解释器模式(Interpreter模式)的基本概念,通过实例展示了如何利用Interpreter模式解决特定领域的问题,特别是涉及频繁变化的业务规则场景。

   Interpeter解释模式:给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。 ——《设计模式》
   在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。此模式在实际应用中并不常见。
  Interpeter解释模式有以下角色:
  如图:
  


  1、Client客户程序:它是Interpreter模式的使用者,我们通常在此对Context进行初步分析,并形成一个表达式树(通常这个树保存在ArrayList中),这个树中的每一个节点表示要进行的操作(Terminal或NonTermianl类型的操作),这项工作通常打包在一个类中,在本例我们把它放在名为Parse的类中进行。 
  2、Context上下文:它就是我们要进行翻译解释的语句,是我们进行操作原材料。
  3、Expression抽象类:它是一个接口,TerminalExpression类与NonterminalExpression类均继承自此类,它定义了Interpret方法,并要求在其子类中实现此方法。
  4、TerminalExpression类: 它继承自Expression抽象类,它针对语句“分解”的功能成分比较少,主要是针对"最终原子"对象的处理。比如本例,对数学计算式分解后得到的整数的处理。
  5、NonterminalExpression类:它继承自Expression抽象类,它针对不同的语法情况需要定义不同的处理方式,所以通常我们需要在此处进行扩展,例如本例我们定义了针对"+"与"-"法的语法处理,如果需要用到"*"与"/",则我们也需要在此另外扩展相应的NonterminalExpression类。

   这里,我们就以一个数学计算式为例来进行说明:我们需要做的工作就是把左边的表达式翻译成右边的形式并加以计算,情况如下:
  "+ 7 8" 处理后 (7+8)=15
  "- 8 2" 处理后 (8-2)=6
  "+ - 3 8 6" 处理后 ((3-8)+6)=1
  "+ 2 - 7 6" 处理后  (2+(7-6))=3

   一、Interpreter模式流程示例 

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Interpreter
{
    
//被Interpreter解释的上下文内容Context
    
//比如把中文的"五千四百三十二"解释为5432,则"五千四百三十二"就是Context
    public class Context
    {
        
public string Name { getset; }

        
public Context(string name)
        {
            Name 
= name;
        }
    }

    
//声明一个接口,定义执行Interpert操作,操作对象就是Context,也即对它进行语法解释
    
//TerminalExpression与NonterminalExpression将继承自此接口
    public abstract class Expression
    {
        
public abstract void Interpret(Context context);
    }

    
//针对上面Context中的"千,百,十"等各种最小的语句结构进行最终的分析
    
//也即,对"五千","四百","三十","二"这样的最小语句结构进行最终分析
    
//例如:"五千四百万"与"五千","四百",它们其实是不同的数字
    
//"五千四百万"中的五千与四百应属于"万位"数
    
//而后面的"五千","四百"而分别属于"千位"与"百位数"
    
//虽然它们属于不的"位数",但针对它们的解释方法是一样的,所以可以放到TerminalExpression中操作
    
//但操作后的结果应放在什么"位数"上,则由各自对应的NonterminalExpression来决定,即由Expression1,Expression2.ExpressionN来对应

    
public class TerminalExpression : Expression
    {
        
public override void Interpret(Context context)
        {
            Console.WriteLine(
"Terminal for {0}.", context.Name);
        }
    }

    
//针对每一种语法情况都需要在此定义一个解释器,例如:"二百三十万" "四千" "三十","五",则针对万,千,十位,个位它们的语法表达规律是不一样的
    
//所以需要针对"万位数","千位数","百位数","十位数","个位数"每一种情况的语法规律定制有所针对性的解释器
    public class NonterminalExpression : Expression
    {
        
public Expression Expression1 { getset; } //可理解为针对"万位数"的解释

        
public Expression Expression2 { getset; } //可理解为针对"千位数"的解释

        
public override void Interpret(Context context)
        {
            Console.WriteLine(
"Nonterminal for {0}.", context.Name);
            Expression1.Interpret(context);
            Expression2.Interpret(context);
        }
    }
}
 在Client中展示流程
            #region  演示流程
             Console.WriteLine(
" -------Interpreter模式处理流程------- " );
            Context context 
=   new  Context( " the context " );
            NonterminalExpression root 
=   new  NonterminalExpression();
            root.Expression1 
=   new  TerminalExpression();
            root.Expression2 
=   new  TerminalExpression();
            root.Interpret(context);
            Console.ReadKey();
            
#endregion

   二、数学计算式的Interpreter模式应用
  1、Context角色:此角色在实际应用中可有可没有,我们在这里并不需要它,但此处为完整,还是给出一个定义 

     public   class  Context
    {
        
public   string  Name {  get set ; }

        
public  Context( string  name)
        {
            Name 
=  name;
        }
    }

  2、Expression抽象类角色

     #region  定义一个Expression接口
    
public   abstract   class  ExpressionBase
    {
        
public   abstract   int  Evaluate();
    }
    
#endregion

  3、TerminalExpression类角色 

ContractedBlock.gif ExpandedBlockStart.gif Code
    #region 定义TerminalExpression
    
#region 定义IntegerExpression类,它是TerrminalExpression
    
public class IntegerExpression : ExpressionBase
    {
        
int _value;

        
public IntegerExpression(int value)
        {
            _value 
= value;
        }

        
public override int Evaluate()
        {
            
return _value;
        }

        
public override string ToString()
        {
            
return _value.ToString();
        }
    }

    
#endregion
    
#endregion

  4、NonterminalExpression类角色 

ContractedBlock.gif ExpandedBlockStart.gif Code
    #region 定义NonterminalExpression
    
//当然,我们还可以加入针对"*"号与"/"号的NonterminalExpression

    
#region AdditionExpression 针对"+"号的NonterminalExpression
    
public class AdditionExpression : ExpressionBase
    {
        ExpressionBase _expr1;
        ExpressionBase _expr2;

        
public AdditionExpression(ExpressionBase expr1, ExpressionBase expr2)
        {
            _expr1 
= expr1;
            _expr2 
= expr2;
        }

        
public override int Evaluate()
        {
            
int value1 = _expr1.Evaluate();
            
int value2 = _expr2.Evaluate();
            
return value1 + value2;
        }

        
public override string ToString()
        {
            
return string.Format("({0} + {1})", _expr1, _expr2);
        }
    }

    
#endregion

    
#region  SubtractionExpression 针对"-"号的NonterminalExpression
    
public class SubtractionExpression : ExpressionBase
    {
        ExpressionBase _expr1;
        ExpressionBase _expr2;

        
public SubtractionExpression(ExpressionBase expr1, ExpressionBase expr2)
        {
            _expr1 
= expr1;
            _expr2 
= expr2;
        }

        
public override int Evaluate()
        {
            
int value1 = _expr1.Evaluate();
            
int value2 = _expr2.Evaluate();
            
return value1 - value2;
        }

        
public override string ToString()
        {
            
return string.Format("({0} - {1})", _expr1, _expr2);
        }

    }

    
#endregion


    
#endregion

  5、定义Parser,它负责对Context进行分解

ContractedBlock.gif ExpandedBlockStart.gif Code
    #region 定义Parser,它负责对Context进行分解
    
//并负责组织TerminalExpression与NontermianlExpression方法对Context进行处理
    public class Parser
    {
        
public ExpressionBase Parse(string polish)
        {
            List
<string> symbols = new List<string>(polish.Split(' '));
            
return ParseNextExpression(symbols);
        }


        
public ExpressionBase ParseNextExpression(List<string> symbols)
        {
            
int value;
            
if (int.TryParse(symbols[0], out value))
            {
                symbols.RemoveAt(
0);
                
return new IntegerExpression(value);
            }
            
else
            {
                
return ParseNonTerminalExpression(symbols);
            }
        }


        
private ExpressionBase ParseNonTerminalExpression(List<string> symbols)
        {
            
string symbol = symbols[0];
            symbols.RemoveAt(
0);

            ExpressionBase expr1 
= ParseNextExpression(symbols);
            ExpressionBase expr2 
= ParseNextExpression(symbols);

            
switch (symbol)
            {
                
case "+":
                    
return new AdditionExpression(expr1, expr2);
                
case "-":
                    
return new SubtractionExpression(expr1, expr2);
                
default:
                    
string message = string.Format("Invalid Symbol ({0})", symbol);
                    
throw new InvalidOperationException(message);
            }
        }
    }
    
#endregion

  6、Client客户程序角色

ContractedBlock.gif ExpandedBlockStart.gif Code
            #region 演示数学计算式的语法解释
            Console.WriteLine(
"-------数学计算工Interpreter模式应用-------");
            Parser parser 
= new Parser();
            
string[] commands = new string[]
            {
                
"+ 7 8",
                
"- 8 2",
                
"+ - 3 8 6",
                
"+ 2 - 7 6",
                
"+ - + - - 2 3 4 + - -5 6 + -7 8 9 10"
            };

            
foreach (string command in commands)
            {
                ExpressionBase expression 
= parser.Parse(command);
                Console.WriteLine(
"{0} = {1}", expression, expression.Evaluate());
            }
            Console.ReadKey();
            
#endregion

  程序如下图:

                        
  运行效果如下图:

                        

总结:
Interpreter 模式的几个要点
1、Interpreter模式的应用场合是中的难点,只有满足Interpreter模式应用“业务规则频繁变化,且类似的模式不断重复出现,并且容易抽象为语法规则的问题”才适合使用Interpreter模式。
2、使用Interpreter 模式来表示文法规则,从而可以使用面向对象技巧来方便地“扩展”文法。
3、Interpreter 模式比较适合简单的文法表示,对于复杂的文法表示,Interperter 模式会产生比较大的类层次结构,需要求助于语法分析生成器这样的标准工具。

 

 

前往:设计模式学习笔记清单
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值