设计模式之解释器模式

时间:2021-07-09 14:43:07
模式定义:
        给定一个语言的文法,即规则,并且定义一个解释器用来解释语言中的句子。该模式描述了
        在怎么样给定一个简单的文法之后,使用该模式来解释这些句子。在解释器模式中定义了一
        个代表语言文法命令的类层次结构,在这个结构中可以存在任何的组合规则,每一个具体的
        解释器都有相同的解释操作,然而,每个解释器都以不同的方式实现公共的解释操作。再解
        释器模式中使用组合的方式将一些类组成一个集合,然后定义出一种语法规则,解释器根据
        已经定义的语法规则执行,生成可执行对象。
        
        mydia语言规则:
        区分大小写、以PROGRAM开始END结尾、PRINTLN表示打印一行并换行、使用FOR...FROM...TO...END
        表示循环
        PROGRAM PRINTLN start.... FOR i FROM 10 TO 20 PRINTLN i PRINTLN end.... END   预生成:
        start....
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        end....
        
遵循原则:
        开闭原则;
        封装变化部分;
适用场合:
        
知识扩展:

        JDK中java.text.Format就是解释器模式。

/**
 * 该类主要用来保存待执行的语句、当前节点、动态参数内容,以及操作这些数据的公共方法。
 * @author xsy
 *
 */
public class Context {
    //待解析的内容
    private final StringTokenizer stringTokenizer;
    //当前命令
    private String currentToken;
    //动态信息
    private Map<String, Object> map = new HashMap<String, Object>();
    
    public Context(String string) {
        super();
        //使用空格表示分隔符
        this.stringTokenizer = new StringTokenizer(string);
    }
    /**
     * 解析文本
     * @return
     */
    public String next(){
        if(this.stringTokenizer.hasMoreTokens()){
            currentToken = this.stringTokenizer.nextToken();
        }else {
            currentToken = null;
        }
        return currentToken;
    }
    /**
     * 判断命令是否正确
     * @param command
     * @return
     */
    public boolean equalsWithCommand(String command){
        if(null == command || !command.equals(currentToken)){
            return false;
        }return true;
    }
    /**
     * 获取当前内容
     * @return
     */
    public String getCurrentToken(){
        return this.currentToken;
    }
    
    public String getTokenContent(String text){
        String string = text;
        if(string != null){
            Iterator<String> itr = this.map.keySet().iterator();
            while (itr.hasNext()) {
                String key = itr.next();
                Object object = map.get(key);
                string = string.replaceAll(key, object.toString());
            }
        }
        return string;
    }
    public void put(String key,Object object ){
        this.map.put(key,object);
    }
    public void clear(String key){
        this.map.remove(key);
    }
}

public interface IExpression {
    /**
     * 解释
     * @param context
     */
    public void parse(Context context);
    /**
     * 执行
     */
    public void execute();
}

public class PrimitiveExpression implements IExpression {
    private Context context;
    private String tokenName;
    private String text;
    public PrimitiveExpression(Context context) {
        this.parse(this.context);
    }

    @Override
    public void execute() {
        if("PRINTLN".equals(this.tokenName))
        System.out.println(this.context.getTokenContent(text));
    }

    @Override
    public void parse(Context context) {
        this.context = context;
        this.tokenName = this.context.getCurrentToken();
        this.context.next();
        if("PRINTLN".equals(this.tokenName)){
            this.text = this.context.getCurrentToken();
            this.context.next();
        }
    }

}

public class ListExpression implements IExpression {

    private Context context;
    private final List<IExpression> list = new ArrayList<IExpression>();
    @Override
    public void execute() {
        Iterator<IExpression> itr = list.iterator();
        while (itr.hasNext()) {
            itr.next().execute();
            
        }
    }

    @Override
    public void parse(Context context) {
        this.context = context;
        while (true) {
            if(this.context.getCurrentToken() == null){
                System.out.println("error!! END is excepted");
                break;
            }else if(this.context.equalsWithCommand("END")){
                this.context.next();
                break;
            }else {
                IExpression expression = new CommandExpression(this.context);
                list.add(expression);
            }
            
        }
    }

}

public class ForExpression implements IExpression {
    private final Context context;
    private IExpression expression;
    private String var;
    private int start;
    private int end;
    public ForExpression(Context context) {
        this.context = context;
        this.parse(this.context);
    }

    @Override
    public void execute() {
        for (int i = start; i <= end; i++) {
            this.context.put(""+this.var, i);
            this.expression.execute();
        }
        this.context.clear(""+this.var);
    }
    

    @Override
    public void parse(Context context) {
        this.context.next();
        while (true) {
            if(this.context.equalsWithCommand("FROM")){
                String nextString = this.context.next();
                start = Integer.parseInt(nextString);
                this.context.next();
            }else if(this.context.equalsWithCommand("TO")){
                String nextString = this.context.next();
                end = Integer.parseInt(nextString);
                this.context.next();
                break;
            }else {
                if(this.var == null){
                    this.var = this.context.getCurrentToken();
                }
                this.context.next();
            }
        }
        this.expression = new ListExpression();
        this.expression.parse(this.context);
    }

}

public class ProgramExpression implements IExpression {

    private final Context context;
    /**
     * 当前命令
     */
    private final static String COMMAND = "PROGRAM";
    /**
     * 下一个表达式
     */
    private IExpression expression;
    
    
    public ProgramExpression(String text) {
        this.context = new Context(text);
        this.parse(this.context);
    }

    @Override
    public void execute() {
        if(!this.context.equalsWithCommand(COMMAND)){
            System.out.println("error!! PROGRAM is excepted");
        }else {
            this.context.next();
            this.expression = new ListExpression();
            this.expression.parse(this.context);
            this.expression.execute();
        }
    }

    @Override
    public void parse(Context context) {
        this.context.next();
    }

}

public class CommandExpression implements IExpression {

    private final Context context;
    private IExpression expression;
    
    public CommandExpression(Context context) {
        this.context = context;
        this.parse(this.context);
    }

    @Override
    public void execute() {
        this.expression.execute();
    }

    @Override
    public void parse(Context context) {
        if(this.context.equalsWithCommand("FOR")){
            expression = new ForExpression(this.context);
        }else{
            expression = new PrimitiveExpression(this.context);
        }
    }

}

测试

public class Client {
    public static void main(String[] args) {
        String str = "PROGRAM PRINTLN start.... FOR i FROM 10 TO 20 PRINTLN i END";
        IExpression expression = new ProgramExpression(str);
        expression.execute();
    }

}