解析器模式

一、模式简介

定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子,用编译语言的方式来分析应用中的实例。
场景:一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候。

  • 角色结构:
  • 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作。
  • 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
  • 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
  • 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
  • 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

二、模式实现

public interface AbstractExpression { -> 抽象表达式
    boolean interpret(String info);
}

public class TerminalExpression implements AbstractExpression { -> 终结表达式
    private Set<String> set = new HashSet<>();

    public TerminalExpression(String[] array){
        set.addAll(Arrays.asList(array));
    }

    @Override
    public boolean interpret(String info) {
        return set.contains(info);
    }
}

public class AndExpression implements AbstractExpression { -> 非终结表达式
    private AbstractExpression city;
    private AbstractExpression card;

    public AndExpression(AbstractExpression city, AbstractExpression card) {
        this.city = city;
        this.card = card;
    }

    @Override
    public boolean interpret(String info) {
        String[] array = info.split("使用");
        if (array.length < 2) return false;
        return city.interpret(array[0]) && card.interpret(array[1]);
    }
}

public class ContextExpression { -> 环境表达式
    private AbstractExpression ZQExpression = new AndExpression(new TerminalExpression(new String[]{"肇庆"}),
            new TerminalExpression(new String[]{"岭南通"}));
    private AbstractExpression GZExpression = new AndExpression(new TerminalExpression(new String[]{"广州"}),
            new TerminalExpression(new String[]{"羊城通", "岭南通"}));

    public void interpret(String info) {
        if (ZQExpression.interpret(info) || GZExpression.interpret(info)) {
            System.out.println(info + ",可行");
        } else {
            System.out.println(info + ",不可行");
        }
    }
}

以不同城市使用不同的公交卡乘车为例子,羊城通公交卡只允许在广州乘车,岭南通公交卡则可以在肇庆或广州乘车。

ContextExpression context = new ContextExpression();
context.interpret("肇庆使用羊城通");
context.interpret("肇庆使用岭南通");
context.interpret("广州使用羊城通");
context.interpret("广州使用岭南通");
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。