读《研磨设计模式》-代码笔记-解释器模式-Interpret

声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/


package design.pattern;

/*
 * 解释器(Interpreter)模式的意图是可以按照自己定义的组合规则集合来组合可执行对象
 * 
 * 代码示例实现XML里面1.读取单个元素的值 2.读取单个属性的值
 * 多个元素或者多个属性的示例书上也有,但稍显复杂,就不做这方面的笔记了
 */


import java.util.ArrayList;
import java.util.Collection;

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

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


abstract class Expression {
    
    //可能返回一个String也可能返回多个。String书上说为了兼容,返回值定义为String数组
    public abstract String[] interpret(Context context);

}

/**
 * Context持有两个Field:
 * 1.整个XML对象(Document document)
 * 2.上一个被处理的元素(Element preElement)
 * 当Expression执行interpret方法时,不断改变Context里的preElement,直到表达式终止为止
 */
class Context {
    
    //上一个被处理的元素
    private Element preElement;
    
    private Document document;
    
    public Context(String filePath) throws Exception {
        this.document = XMLUtil.getRoot(filePath);
    }
    
    public void redoInit() {
        this.preElement = null;
    }

    /**
     * 根据父元素和子元素的名字来获取子元素
     * @param preElement    父元素
     * @param elementName   要找的元素的名字
     * @return 找到的元素
     */
    public Element getCurElement(Element preElement, String elementName) {
        Element result = null;
        NodeList nodeList = preElement.getChildNodes();
        
        //遍历所有直接子元素(孙子元素不算)
        for (int i = 0, len = nodeList.getLength(); i < len ;i ++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                Element element = (Element)node;
                if (element.getNodeName().equals(elementName)) {
                    result = element;
                    break;
                }
            }
        }
        return result;
    }
    
    public Element getPreElement() {
        return preElement;
    }

    public void setPreElement(Element preElement) {
        this.preElement = preElement;
    }

    public Document getDocument() {
        return document;
    }
    
    
}

/**
 * 读取XML文件的帮助类。提供一个方法根据文件名返回XML Document对象
 */
class XMLUtil {
    
    public static Document getRoot(String filePath) throws Exception {
        Document doc = null;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        doc = builder.parse(filePath);
        doc.normalize();
        return doc;
    }
}


//非终结元素的解释器
class ElementExpression extends Expression {

    //在下面的测试,Expression的childExpressions只有一个。childExpressions.size() = 1
    private Collection<Expression> childExpressions = new ArrayList<Expression>();     
    
    private String elementName;
    
    public ElementExpression(String elementName) {
        this.elementName = elementName;
    }
    
    public void add(Expression expression) {
        this.childExpressions.add(expression);
    }
    
    public void remove(Expression expression) {
        this.childExpressions.remove(expression);
    }
    
    public String[] interpret(Context context) {
        Element parent = context.getPreElement();
        Element curElement = null;
        if (parent == null) {       //说明是根元素
            Document dom = context.getDocument();
            curElement = dom.getDocumentElement();        //Document.getDocumentElement,取得根元素
        } else {
            curElement = context.getCurElement(parent, elementName);
        }
        context.setPreElement(curElement);
        
        String[] ss = null;
        for (Expression expression : childExpressions) {
            
            //这里写得有歧义。如果childExpressions.size > 1,那ss只能获取到最后一个childExpression的返回值
            //不过由于测试过程中,childExpressions.size = 1,也就问题不大
            ss = expression.interpret(context);     
        }
        return ss;
    }
    
    public String toString() {
        return "elementName = " + elementName + ", childExpressions = " + childExpressions;
    }
    
}


//元素作为终结符的解释器
class ElementTerminatorExpression extends Expression {

    private String elementName;
    
    public ElementTerminatorExpression(String elementName) {
        this.elementName = elementName;
    }
    
    public String[] interpret(Context context) {
        Element parent = context.getPreElement();
        Element curElement = null;
        if (parent == null) {       //说明是根元素
            curElement = context.getDocument().getDocumentElement();        //返回根元素
        } else {
            curElement = context.getCurElement(parent, elementName);
        }
        context.setPreElement(curElement);
        //获取元素的值
        String finalValue = curElement.getFirstChild().getNodeValue();
        return new String[]{finalValue};
    }
    
}

//属性作为终结符的解释器
class PropertyTerminatorExpression extends Expression {
    
    private String propertyName;
    
    public PropertyTerminatorExpression(String propertyName) {
        this.propertyName = propertyName;
    }
    
    public String[] interpret(Context context) {
        //直接获取元素的属性的值
        String finalValue = context.getPreElement().getAttribute(this.propertyName);
        return new String[]{finalValue};
    }
    
}

//这个类是用来测试的
public class InterpreterPattern {

    public static void main(String[] args) throws Exception {
        /*
<?xml version="1.0" encoding="UTF-8"?>
<root id="rootId">
    <a>
       <b>
           <c name="testC">12345</c>
           <d id="1">d1</d>
           <d id="2">d2</d>
           <d id="3">d3</d>
           <d id="4">d4</d>
       </b>
    </a>
</root>
         */
        Context context = new Context("d:/interpretPattern.xml");
        //构建要查找的表达式的语法树,例如我们要查看元素c的值,表达式是root/a/b/c
        //元素作为终结符
        ElementExpression root = new ElementExpression("root");
        ElementExpression a = new ElementExpression("a");
        ElementExpression b = new ElementExpression("b");
        ElementTerminatorExpression c = new ElementTerminatorExpression("c");
        root.add(a);
        a.add(b);
        b.add(c);
        String[] ss = root.interpret(context);
        System.out.println("c = " + ss[0]);
        
        //元素属性作为终结符,例如root/a/b/c.name
        context.redoInit();
        ElementExpression roott = new ElementExpression("root");
        ElementExpression aa = new ElementExpression("a");
        ElementExpression bb = new ElementExpression("b");
        ElementExpression cc= new ElementExpression("c");
        PropertyTerminatorExpression prop = new PropertyTerminatorExpression("name");
        roott.add(aa);
        aa.add(bb);
        bb.add(cc);
        cc.add(prop);
        ss = roott.interpret(context);
        System.out.println("c name = " + ss[0]);
        
        context.redoInit();
        ss = roott.interpret(context);
        System.out.println("c name = " + ss[0]);
    }

}


你可能感兴趣的:(java,设计模式)