`

设计模式(20)- 解释器模式

阅读更多

解释器模式

1.定义

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

2.示例代码

    以解析xml为例,说明解释器模式。

   

/*要解析的xml示例文件*/
<?xml version="1.0" encoding="UTF-8">
<root id="rootId">
    <a>
         <b>
               <c name="testC">123456</c>
               <d id="1">d1</d>
               <d id="2">d2</d>
               <d id="3">d3</d>
               <d id="4">d4</d>
         </b>
    </a>
</root>

 

 

/*用于处理自定义xml取值表达式的接口*/
public abstract class ReadXmlExpression{
    /*解释表达式*/
    public abstract String[] interpret(Context c);
}

/*上下文,用来包含解释器需要的一些全局信息*/
public class Context {

    /*Dom解析Xml的Document对象*/

    private Document document = null;

    /*上一次被处理的多个元素 */

    private List<Element> preEles = new ArrayList<Element>();

    /*构造方法 需要读取的xml的路径和名字*/
    public Context(String filePathName) throws Exception{

       //通过辅助的Xml工具类来获取被解析的xml对应的Document对象
       this.document = XmlUtil.getRoot(filePathName);

    }

    /*重新初始化上下文*/
    public void reInit(){
       preEles = new ArrayList<Element>();
    }
    /*各个Expression公共使用的方法,根据父元素和当前元素的名称来获取当前的多个元素的集合*/
    public List<Element> getNowEles(Element pEle,String eleName){
       List<Element> elements = new ArrayList<Element>();
       NodeList tempNodeList = pEle.getChildNodes();
       for(int i=0;i<tempNodeList.getLength();i++){
           if(tempNodeList.item(i) instanceof Element){
              Element nowEle = (Element)tempNodeList.item(i);
              if(nowEle.getTagName().equals(eleName)){
                  elements.add(nowEle);
              }
           }
       }
       return elements;
    }

    public Document getDocument() {
       return document;
    }
    public List<Element> getPreEles() {
       return preEles;
    }
    public void setPreEles(List<Element> nowEles) {
       this.preEles = nowEles;
    }
}

/*单个元素作为非终结符的解释器*/
public class ElementExpression extends ReadXmlExpression{
    /*用来记录组合的ReadXmlExpression元素*/
    private Collection<ReadXmlExpression> eles = new ArrayList<ReadXmlExpression>();
    /* 元素的名称*/
    private String eleName = "";
    public ElementExpression(String eleName){
       this.eleName = eleName;
    }
    public boolean addEle(ReadXmlExpression ele){
       this.eles.add(ele);
       return true;
    }
    public boolean removeEle(ReadXmlExpression ele){
       this.eles.remove(ele);
       return true;
    }  
    public String[] interpret(Context c) {
       //先取出上下文里的父级元素
       List<Element> pEles = c.getPreEles();
       Element ele = null;
       //把当前获取的元素放到上下文里面
       List<Element> nowEles = new ArrayList<Element>();      
       if(pEles.size()==0){
           //说明现在获取的是根元素
           ele = c.getDocument().getDocumentElement();
           pEles.add(ele);
           c.setPreEles(pEles);
       }else{
           for(Element tempEle : pEles){
              nowEles.addAll(c.getNowEles(tempEle, eleName));
              if(nowEles.size()>0){
                  //找到一个就停止
                  break;
              }
           }
           List<Element> tempList = new ArrayList<Element>();
           tempList.add(nowEles.get(0));
           c.setPreEles(tempList);
       }   
       //循环调用子元素的interpret方法
       String [] ss = null;
       for(ReadXmlExpression tempEle : eles){
           ss = tempEle.interpret(c);
       }
       return ss;
    }
}

/* 元素作为终结符对应的解释器*/
public class ElementTerminalExpression  extends ReadXmlExpression{
    /* 元素的名字*/
    private String eleName = "";
    public ElementTerminalExpression(String name){
       this.eleName = name;
    }  
    public String[] interpret(Context c) {
       //先取出上下文里的当前元素作为父级元素
       List<Element> pEles = c.getPreEles();
       //查找到当前元素名称所对应的xml元素
       Element ele = null;
       if(pEles.size() == 0){
           //说明现在获取的是根元素
           ele = c.getDocument().getDocumentElement();
       }else{
           //获取当前的元素
           ele = c.getNowEles(pEles.get(0), eleName).get(0);
       } 
       //然后需要去获取这个元素的值
       String[] ss = new String[1];
       ss[0] = ele.getFirstChild().getNodeValue();
       return ss;
    }
}

/* 以多个元素的属性做为终结符的解释处理对象*/
public class PropertysTerminalExpression extends ReadXmlExpression{
    /* 属性名字*/
    private String propName;
    public PropertysTerminalExpression(String propName){
       this.propName = propName;
    }  
    public String[] interpret(Context c) {
       //获取最后的多个元素
       List<Element> eles = c.getPreEles();     
       String[] ss = new String[eles.size()];
       //循环多个元素,获取每个的属性的值
       for(int i=0;i<ss.length;i++){
           ss[i] = eles.get(i).getAttribute(this.propName);
       }
       return ss;
    }
}

/* 以多个元素作为终结符的解释处理对象*/
public class ElementsTerminalExpression  extends ReadXmlExpression{
    /*元素的名称*/
    private String eleName = "";
    public ElementsTerminalExpression(String name){
       this.eleName = name;
    }   
    public String[] interpret(Context c) {
       //先取出上下文里的父级元素
       List<Element> pEles = c.getPreEles();
       //获取当前的多个元素
       List<Element> nowEles = new ArrayList<Element>();      
       for(Element ele : pEles){
           nowEles.addAll(c.getNowEles(ele, eleName));
       } 
       //然后需要去获取这些元素的值
       String[] ss = new String[nowEles.size()];
       for(int i=0;i<ss.length;i++){
           ss[i] = nowEles.get(i).getFirstChild().getNodeValue();
       }
       return ss;
    }
}

/*多个元素做为非终结符的解释处理对象*/
public class ElementsExpression extends ReadXmlExpression{
    /* 用来记录组合的ReadXmlExpression元素*/
    private Collection<ReadXmlExpression> eles = new ArrayList<ReadXmlExpression>();
    /*元素名字*/
    private String eleName = "";
    public ElementsExpression(String eleName){
       this.eleName = eleName;
    }  
    public String[] interpret(Context c) {
       //先取出上下文里的父级元素
       List<Element> pEles = c.getPreEles();
       //把当前获取的元素放到上下文里面,这次是获取多个元素
       List<Element> nowEles = new ArrayList<Element>();     
       for(Element ele : pEles){
           nowEles.addAll(c.getNowEles(ele, eleName));
       }
       c.setPreEles(nowEles);     
       //循环调用子元素的interpret方法
       String [] ss = null;
       for(ReadXmlExpression ele : eles){
           ss = ele.interpret(c);
       }
       return ss;
    }  
    public boolean addEle(ReadXmlExpression ele){
       this.eles.add(ele);
       return true;
    }
    public boolean removeEle(ReadXmlExpression ele){
       this.eles.remove(ele);
       return true;
    }
}

  

/*测试获取多个元素的值的情况*/
public class Client {
    public static void main(String[] args) throws Exception {
       //准备上下文
       Context c = new Context("InterpreterTest.xml");
       //想要获取多个d元素的值,也就是如下表达式的值:"root/a/b/d$"
       //首先要构建解释器的抽象语法树
       ElementExpression root = new ElementExpression("root");
       ElementExpression aEle = new ElementExpression("a");
       ElementExpression bEle = new ElementExpression("b");
       ElementsTerminalExpression dEle = new ElementsTerminalExpression("d");
       //组合起来
       root.addEle(aEle);
       aEle.addEle(bEle);
       bEle.addEle(dEle);      
       //调用
       String ss[] = root.interpret(c);
       for(String s : ss){
           System.out.println("d的值是="+s);  
       }
    }
}

/*测试一下获取多个属性值的情况*/
public class Client {
    public static void main(String[] args) throws Exception {
       //准备上下文
       Context c = new Context("InterpreterTest.xml");
       //想要获取d元素的id属性,也就是如下表达式的值:"a/b/d$.id$"
       //首先要构建解释器的抽象语法树
       ElementExpression root = new ElementExpression("root");
       ElementExpression aEle = new ElementExpression("a");
       ElementExpression bEle = new ElementExpression("b");
       ElementsExpression dEle = new ElementsExpression("d");
       PropertysTerminalExpression prop =
       new PropertysTerminalExpression("id");
       //组合
       root.addEle(aEle);
       aEle.addEle(bEle);
       bEle.addEle(dEle);
       dEle.addEle(prop);
       //调用
       String ss[] = root.interpret(c);
       for (String s : ss) {
           System.out.println("d的属性id值是=" + s);
       }
    }
}

   

/*用来封装每一个解析出来的元素对应的属性*/
public class ParserModel {
    /* 是否单个值*/
    private boolean singleVlaue;
    /*是否属性,不是属性就是元素*/
    private boolean propertyValue;
    /*是否终结符*/
    private boolean end;
    public boolean isEnd() {
       return end;
    }
    public void setEnd(boolean end) {
       this.end = end;
    }
    public boolean isSingleVlaue() {
       return singleVlaue;
    }
    public void setSingleVlaue(boolean oneVlaue) {
       this.singleVlaue = oneVlaue;
    }
    public boolean isPropertyValue() {
       return propertyValue;
    }
    public void setPropertyValue(boolean propertyValue) {
       this.propertyValue = propertyValue;
    }
}

/* 根据语法来解析表达式,转换成为相应的抽象语法树*/
public class Parser {
    /*私有化构造器,避免外部无谓的创建对象实例*/
    private Parser(){
    }
    //定义几个常量,内部使用
    private final static String BACKLASH = "/";
    private final static String DOT = ".";
    private final static String DOLLAR = "$";
    /*按照分解的先后记录需要解析的元素的名称*/
    private static List<String> listEle = null;
    /*传入一个字符串表达式,通过解析,组合成为一个抽象的语法树*/
    public static ReadXmlExpression parse(String expr){
       //先初始化记录需解析的元素的名称的集 会
       listEle = new ArrayList<String>();
       //第一步:分解表达式,得到需要解析的元素名称和该元素对应的解析模型
       Map<String,ParserModel> mapPath = parseMapPath(expr);      
       //第二步:根据节点的属性转换成为相应的解释器对象
       List<ReadXmlExpression> list = mapPath2Interpreter(mapPath);
       //第三步:组合抽象语法树,一定要按照先后顺序来组合,
       //否则对象的包含关系就乱了
       ReadXmlExpression returnRe = buildTree(list);
       return returnRe;        
    }
/*----------------------开始实现第一步-----------------------*/
    /* 按照从左到右顺序来分解表达式,得到需要解析的元素名称,
     * 还有该元素对应的解析模型
     * @param expr 需要分解的表达式
     * @return 得到需要解析的元素名称,还有该元素对应的解析模型
     */
    private static Map<String,ParserModel> parseMapPath(String expr){
       //先按照/分割字符串
       StringTokenizer tokenizer = new StringTokenizer(expr, BACKLASH);
       //初始化一个map用来存放分解出来的值
       Map<String,ParserModel> mapPath = new HashMap<String,ParserModel>();
       while (tokenizer.hasMoreTokens()) {
           String onePath = tokenizer.nextToken();
           if (tokenizer.hasMoreTokens()) {
              //还有下一个值,说明这不是最后一个元素
              //按照现在的语法,属性必然在最后,因此也不是属性
              setParsePath(false,onePath,false,mapPath);
           } else {
              //说明到最后了
              int dotIndex = onePath.indexOf(DOT);
              if (dotIndex > 0) {
                  //说明是要获取属性的值,那就按照"."来分割,
                  //前面的就是元素名字,后面的是属性的名字
                  String eleName = onePath.substring(0, dotIndex);
                  String propName = onePath.substring(dotIndex + 1);
                  //设置属性前面的那个元素,自然不是最后一个,也不是属性
                  setParsePath(false,eleName,false,mapPath);
                  //设置属性,按照现在的语法定义,属性只能是最后一个
                  setParsePath(true,propName,true,mapPath);
              } else {
                  //说明是取元素的值,而且是最后一个元素的值
                  setParsePath(true,onePath,false,mapPath);
              }
              break;
           }
       }
       return mapPath;
    }
    /*按照分解出来的位置和名称来设置需要解析的元素名称,
     * 还有该元素对应的解析模型
     * @param end 是否是最后一个
     * @param ele 元素名称
     * @param propertyValue 是否是取属性
     * @param mapPath 设置需要解析的元素名称,还有该元素对应的解析模型的Map
     */
    private static void setParsePath(boolean end,String ele ,boolean propertyValue,Map<String,ParserModel> mapPath){
       ParserModel pm = new ParserModel();
       pm.setEnd(end);
       //如果带有$符号就说明不是一个值
       pm.setSingleVlaue(!(ele.indexOf(DOLLAR)>0));
       pm.setPropertyValue(propertyValue);             
       //去掉$
       ele = ele.replace(DOLLAR, "");
       mapPath.put(ele,pm);
       listEle.add(ele);
    }
/*----------------------第一步实现结束-----------------------*/

/*----------------------开始实现第二步-----------------------*/  
    /* 把分解出来的元素名称,根据对应的解析模型转换成为相应的解释器对象
     * @param mapPath 分解出来的需解析的元素名称,还有该元素对应的解析模型
     * @return 把每个元素转换成为相应的解释器对象后的集合
     */
    private static List<ReadXmlExpression> mapPath2Interpreter(Map<String,ParserModel> mapPath){
       List<ReadXmlExpression> list = new ArrayList<ReadXmlExpression>();
       //一定要按照分解的先后顺序来转换成解释器对象
       for(String key : listEle){
           ParserModel pm = mapPath.get(key);
           ReadXmlExpression obj = null;
           if(!pm.isEnd()){
              if(pm.isSingleVlaue()){
                  //不是最后一个,是一个值,转化为
                  obj = new ElementExpression(key);            
              }else{
                  //不是最后一个,是多个值,转化为
                  obj = new ElementsExpression(key);
              }
           }else{
              if(pm.isPropertyValue()){
                  if(pm.isSingleVlaue()){
                     //是最后一个,是一个值,取属性的值,转化为
                     obj = new PropertyTerminalExpression(key);
                  }else{
                     //是最后一个,是多个值,取属性的值,转化为
                     obj = new PropertysTerminalExpression(key);
                  }
              }else{
                  if(pm.isSingleVlaue()){
                     //是最后一个,是一个值,取元素的值,转化为
                     obj = new ElementTerminalExpression(key);
                  }else{
                     //是最后一个,是多个值,取元素的值,转化为
                     obj = new ElementsTerminalExpression(key);
                  }
              }
           }
           //把转换后的对象添加到集合中
           list.add(obj);
       }
        return list;
    }
/*----------------------第二步实现结束-----------------------*/  

/*----------------------开始实现第三步-----------------------*/  
    private static ReadXmlExpression buildTree(List<ReadXmlExpression> list){
       //第一个对象,也是返回去的对象,就是抽象语法树的根
       ReadXmlExpression returnRe = null;
       //定义上一个对象
       ReadXmlExpression preRe = null;
       for(ReadXmlExpression re : list){        
           if(preRe==null){
              //说明是第一个元素
              preRe = re;
              returnRe = re;
           }else{
              //把元素添加到上一个对象下面,同时把本对象设置成为oldRe,
              //作为下一个对象的父结点
              if(preRe instanceof ElementExpression){
                  ElementExpression ele = (ElementExpression)preRe;
                  ele.addEle(re);
                  preRe = re;
              }else if(preRe instanceof ElementsExpression){
                  ElementsExpression eles = (ElementsExpression)preRe;
                  eles.addEle(re);
                  preRe = re;
              }
           }
       }
       return returnRe;
    }
/*----------------------第三步实现结束-----------------------*/
}

   

/* 使用解析器
*想要获取c元素的值,表达式为:“root/a/b/c”
*想要获取c元素的name属性值,表达式为:“root/a/b/c.name”
*想要获取d元素的值,表达式为:“root/a/b/d$”,获取d的属性测试
*/
public class Client {
    public static void main(String[] args) throws Exception {
       //准备上下文
       Context c = new Context("InterpreterTest.xml");
       //通过解析器获取抽象语法树
       ReadXmlExpression re = Parser.parse("root/a/b/d$.id$");
       //请求解析,获取返回值
       String ss[] = re.interpret(c);
       for (String s : ss) {
           System.out.println("d的属性id值是=" + s);
       }   
       //如果要使用同一个上下文,连续进行解析,需要重新初始化上下文对象
       c.reInit();
       ReadXmlExpression re2 = Parser.parse("root/a/b/d$");
       //请求解析,获取返回值
       String ss2[] = re2.interpret(c);
       for (String s : ss2) {
           System.out.println("d的值是=" + s);
       }
    }
}

   

3.实际应用

       解释器模式通过一个解释器对象处理一个语法规则的方式,把复杂的功能分离开;然后选择需要被执行的功能,并把这些功能组合成为需要被解释执行的抽象语法树;然后再按照抽象语法树来解释执行,实现相应的功能。

解释器模式的本质:分离实现,解释执行

 

分享到:
评论

相关推荐

    设计模式----解释器模式

    解释器模式(Interpreter Pattern)是25种经典设计模式之一,主要应用于创建一个解析语言或者表达式的方式。在本篇文章中,我们将深入探讨解释器模式的概念、结构以及其在实际开发中的应用。 解释器模式是一种行为...

    JAVA-设计模式-行为型模式-解释器模式

    JAVA-设计模式-行为型模式-解释器模式

    设计模式精解-GoF-23种设计模式解析--附C++源代码

    - 解释器模式(Interpreter):给定一种语言,定义它的文法表示,并提供一个解释器来处理这种语言中的句子。 - 迭代器模式(Iterator):提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 - 中介者...

    c++设计模式-行为型模式-解释器模式

    c++设计模式-行为型模式-解释器模式;qt工程;c++简单源码; 解释器(Interpreter)模式的定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式...

    设计模式课件大全

    设计模式12-解释器模式 设计模式13-迭代器模式 设计模式14-中介者模式、备忘录模式 设计模式15-观察者模式、状态模式 设计模式16-策略模式、模板方法、访问者 此PPT实例便于理解,对于深入理解OO思想有很大帮助。

    设计模式-解释器模式

    **解释器模式**是一种行为设计模式,它提供了一种方式来表示语言或表达式的语法,并通过解析这些语法来执行相关操作。在iOS开发中,解释器模式常常用于处理简单的脚本或表达式,例如在运行时计算数学表达式、解析...

    java常用设计模式-解释器模式

    解释器模式是一种行为设计模式,它定义了一种语言和该语言的解释器,使得可以使用该语言来表达一些特定的操作。该模式适用于需要解释一些特定语言的场景,例如编译器、表达式计算器等。 在 Java 中,可以使用抽象...

    设计模式精解-GoF 23种设计模式解析附C++.pdf

    - **Interpreter模式**:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 #### 4. 总结 设计模式的学习不仅是为了记住每种模式的应用场景,更重要的是理解其...

    设计模式精解-GoF23种设计模式解析附C++实现源码

    - 解释器模式(Interpreter):给定一种语言,定义它的文法表示,并提供一个解释器来处理这种语言中的句子。 - 迭代器模式(Iterator):提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 - 中介者...

    java设计模式-解释器模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段...

    设计模式-解释器模式(讲解及其实现代码)

    **解释器模式**是一种行为设计模式,它提供了一种方式来表示语言的语法,并通过类和对象解析这种语法。在编程领域,解释器模式常用于创建简单的语言或表达式解析器,例如配置文件、计算器应用或者SQL查询的简化版本...

    java设计模式---诙谐易懂版

    代理模式(Proxy Pattern)、单例模式(Singleton Pattern)、工厂方法模式(Factory Method Pattern)、抽象...解释器模式(Interpreter Pattern)、享元模式(Flyweight Pattern)、备忘录模式(Memento Pattern)等...

    设计模式精解-GoF 23种设计模式解析附C++实现源码.pdf

    - **3.11 Interpreter模式**:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 - **应用场景**:可以将一个需要解释执行的语言中的句子表示为一个抽象语法树时...

    设计模式精解-GoF 23种设计模式解析附C++实现源码 完整版

    - 解释器模式:给定一种语言,定义其文法表示,并提供一个解释器来处理这种语言中的句子。 - 迭代器模式:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 - 观察者模式:定义对象间的一对多依赖...

    Java设计模式----通俗易懂版

    - 解释器模式:提供一个语言的文法表示,并定义了一个接口,用于解释语言中的句子。 - 迭代器模式:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 - 中介者模式:用一个中介对象来封装一系列的...

    设计模式精解-GoF 23种设计模式

    16. **解释器模式**:定义了一个表达式接口,让相关类实现这个接口来解释特定的语言。 17. **迭代器模式**:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 18. **中介者模式**:定义一个中介对象来...

    新版设计模式手册 - C#设计模式(第二版)

    比如命令模式、解释器模式、迭代器模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。C#的事件和委托系统使得实现如观察者模式变得非常直观。 在C#设计模式(第二版)中,作者可能会...

    设计模式之解释器

    解释器模式是一种行为型设计模式,主要用于处理语言的文法规则、算术规则等问题。它通过定义语言的文法,并根据该文法来解释句子,使得我们可以用统一的方式处理各种语言结构。本文将通过具体的例子——加减运算来...

Global site tag (gtag.js) - Google Analytics