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 解释器的缺点
语法分析会引起类膨胀,解释采用递归方法,调试问题麻烦,而且存在效率问题。