[设计模式]解释器模式

1. 定义

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

  这里的文法,就是我们通常所说的“语法规则”

2. 类图

  

3. 实例

  

package com.jerry.designpattern.demo;
/**
 * 用于处理自定义xml解释表达式的接口
 * @author Jerry
 * @date 2015年2月4日 下午10:24:41
 */
public abstract class ReadXmlExpression {
    /**
     * 解释表达式
     * @param expression
     * @return 为了通用,返回至可能存在一个或多个,统一使用数组返回
     */
    public abstract String[] interpret(Context c);
}

package com.jerry.designpattern.demo;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;

/**
 * 元素非终止表达式
 * @author Jerry
 * @date 2015年2月4日 下午10:29:44
 */
public class ElementExpression extends ReadXmlExpression{
    private List<ReadXmlExpression> children = new ArrayList<>();
    
    private String eltName;
    
    public ElementExpression(String eltName) {
        this.eltName = eltName;
    }
    
    public void addElt(ReadXmlExpression elt) {
        this.children.add(elt);
    }
    
    public void removeElt(ReadXmlExpression elt) {
        this.children.remove(elt);
    }
    
    @Override
    public String[] interpret(Context c) {
        // TODO Auto-generated method stub
        Element preElt = c.getPreElt();
        
        if (preElt == null) {
            c.setPreElt(c.getDoc().getDocumentElement());
        } else {
            c.setPreElt(c.getNowElt(preElt, eltName));
        }
        
        String[] ss = null;
        
        for (ReadXmlExpression rxe: children) {
            ss = rxe.interpret(c);
        }
        
        return ss;
    }

}

package com.jerry.designpattern.demo;

import org.w3c.dom.Element;

/**
 * 元素终止表达式
 * @author Jerry
 * @date 2015年2月4日 下午10:53:42
 */
public class ElementTerminalException extends ReadXmlExpression{

    private String eltName;
    
    public ElementTerminalException(String eltName) {
        this.eltName = eltName;
    }
    
    @Override
    public String[] interpret(Context c) {
        // TODO Auto-generated method stub
//        Element preElt = c.getPreElt();
//        Element nowElt = c.getNowElt(preElt, this.eltName);
//        
//        String[] ss = new String[1];
//        ss[0] = nowElt.getTextContent();
//        return ss;
        
        
        Element preElt = c.getPreElt();
        Element nowElt = null;
        if (preElt == null) {
            nowElt = c.getDoc().getDocumentElement();
            c.setPreElt(nowElt);
        } else {
            nowElt = c.getNowElt(preElt, this.eltName);
            c.setPreElt(nowElt);
        }
        String[] ss = new String[1];
        ss[0] = nowElt.getFirstChild().getNodeValue();
        return ss;
    }
    
}

package com.jerry.designpattern.demo;

import org.w3c.dom.Element;

/**
 * 属性终止表达式
 * @author Jerry
 * @date 2015年2月4日 下午10:56:57
 */
public class PropertyTerminalExpression extends ReadXmlExpression{
    private String propertyName;
    
    public PropertyTerminalExpression(String propertyName) {
        this.propertyName = propertyName;
    }

    @Override
    public String[] interpret(Context c) {
        // TODO Auto-generated method stub
        Element preElt = c.getPreElt();
        String value = preElt.getAttribute(propertyName);
        String[] ss = new String[1];
        ss[0] = value;
        return ss;
    }
}

package com.jerry.designpattern.demo;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 
 * @author Jerry
 * @date 2015年2月4日 下午10:23:25
 */
public class Context {
    /**
     * 前一个元素
     */
    private Element preElt;
    
    /**
     * xml document
     */
    private Document doc;
    
    public Context(String fileName) throws Exception {
        this.doc = XMLUtils.getRoot(fileName);
    }
    
    /**
     * 根据父元素和当前元素名称,查找当前元素
     * @param pElt
     * @param eltName
     * @return
     */
    public Element getNowElt(Element pElt, String eltName) {
        Element elt = null;
        NodeList nodeList = pElt.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                Element tempElt = (Element)node;
                if (tempElt.getTagName().equals(eltName)) {
                    elt = tempElt;
                    break;
                }
            }
        }
        return elt;
    }
    
    public void reInit() {
        this.doc = null;
    }
    
    public void setPreElt(Element preElt) {
        this.preElt = preElt;
    }
    
    public Element getPreElt() {
        return preElt;
    }
    
    public Document getDoc() {
        return doc;
    }
}

package com.jerry.designpattern.demo;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

public class XMLUtils {
    public static Document getRoot(String fileName) throws Exception {
        Document doc = null;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        doc = builder.parse(fileName);
        doc.normalize();//去掉xml文档中作为格式化内容的空白而映射在Dom树种的TextNode对象
        return doc;
    }
}

package com.jerry.designpattern.demo;

/**
 * 
 * @author Jerry
 * @date 2015年2月4日 下午10:59:37
 */
public class Client {
    public static void main(String[] args) throws Exception {
        Context ctx = new Context("interpret.xml");
        /**
         * 读取a/b/c c元素的值
         */
//        ElementExpression root = new ElementExpression("root");
//        ElementExpression aEltExp = new ElementExpression("a");
//        ElementExpression bEltExp = new ElementExpression("b");
//        ElementTerminalException cEltTeExp = new ElementTerminalException("c");
//        root.addElt(aEltExp);
//        aEltExp.addElt(bEltExp);
//        bEltExp.addElt(cEltTeExp);
        //String[] ss = root.interpret(ctx);
        //System.out.println("root/a/b/c c元素的值为:" + ss[0]);
        
        /**
         * 读取root/a/b/c c元素name属性的值
         */
        ElementExpression root = new ElementExpression("root");
        ElementExpression aEltExp = new ElementExpression("a");
        ElementExpression bEltExp = new ElementExpression("b");
        ElementExpression cEltExp = new ElementExpression("c");
        PropertyTerminalExpression proTerExp = new PropertyTerminalExpression("name");
        root.addElt(aEltExp);
        aEltExp.addElt(bEltExp);
        bEltExp.addElt(cEltExp);
        cEltExp.addElt(proTerExp);
        String[] ss = root.interpret(ctx);
        System.out.println("root/a/b/c c元素name属性的值为:" + ss[0]);
    }
}

4. 解释器模式的应用

  4.1 解释器的优点

    解释器是一个简单语法分析工具,最大的特点是其扩展性,修改语法规则只要修改相应的非终结点表达式,若增加语法,只需要增加相应的非终结点类就可以了

  4.2 解释器的缺点

    语法分析会引起类膨胀,解释采用递归方法,调试问题麻烦,而且存在效率问题。

原文地址:https://www.cnblogs.com/jerry19890622/p/4376483.html