行为型模式 - 解释器模式

系列文章目录

设计模式 - 设计原则

创建型模式 - 单例模式(一)
创建型模式 - 工厂模式(二)
创建型模式 - 原型模式(三)
创建型模式 - 建造者模式(四)

结构型模式 - 适配器模式(一)
结构型模式 - 桥接模式(二)
结构型模式 - 装饰器模式(三)
结构型模式 - 组合模式(四)
结构型模式 - 外观模式(五)
结构型模式 - 享元模式(六)
结构型模式 - 代理模式(七)

行为型模式 - 模板方法模式(一)
行为型模式 - 命令模式(二)
行为型模式 - 访问者模式(三)
行为型模式 - 迭代器模式(四)
行为型模式 - 观察者模式(五)
行为型模式 - 中介者模式(六)
行为型模式 - 备忘录模式(七)
行为型模式 - 解释器模式(八)
行为型模式 - 状态模式(九)
行为型模式 - 策略模式(十)
行为型模式 - 责任链模式(十一)


文章目录



前言

代码地址


一、解释器模式

1.1 解释器模式介绍

  • 解释器(Interpreter)模式:
    • 给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解释器来解释语言中的句子;
    • 也就是说,用编译语言的方式来分析应用中的实例,这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文;

1.2 解释器模式结构

行为型模式 - 解释器模式

  • 抽象表达式(Abstract Expression)角色:

    • 定义解释器接口,约定解释器的解释操作,主要包含解释方法 interpret();
  • 终结表达式(Terminal Expression)角色:

    • 是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应;
  • 非终结符表达式(NonTerminal Expression)角色:

    • 也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每一条规则都对应于一个非终结表达式;
  • 环境(Context)角色:

    • 通常包含各个解释器需要的数据或公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值;
  • 客户端(Client)角色:

    • 主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法;

二、实现

例子:

  • 张三所在公司对于不同的省市不同的职业的有不同政策

2.1 解释器实现

行为型模式 - 解释器模式

package com.dozezz.designpattern.interpreter;

/**
 * 抽象表达式类
 *
 * 身份信息表达式
 */
public abstract class IDCardAbstractExpression {

    /**
     * 定义解析逻辑
     * 假设我们要解析的信息格式是:
     * 北京:张三-程序员
     * 天津:李四-PM
     * 河南:王五-PO
     * 表达式 ‘:’以前是地域,‘-‘ 以后是职业:
     * @param expression
     * @return
     */
    abstract boolean interpret(String expression);
}
package com.dozezz.designpattern.interpreter;

import java.util.Set;

/**
 * 终结表达式(多少种解析规则就需要定义多少种规则类)
 */
public class TerminalExpression extends IDCardAbstractExpression {

//    IDCardExpression childExp;

    /**
     * 存放解析数据
     */
    Set<String> data;

    /**
     * 定义解析用的符号比如 “-”
     */
    String symbol;

    public TerminalExpression(Set<String> data, String symbol) {
        this.data = data;
        this.symbol = symbol;
    }

    @Override
    boolean interpret(String expression) {
//        先按照指定符号分割
        String[] split = expression.split(symbol);
        for (String s : split) {
            if (data.contains(s)) {
                return true;
            }
        }

//        可以继续子解析
//        childExp.interpret(expression);
        return false;
    }
}
package com.dozezz.designpattern.interpreter;

import java.util.Set;

/**
 * 非终结表达式
 */
public class OrExpression extends IDCardAbstractExpression {

    /**
     * 组合终结表达式,最终的判断结果是总结表达式判断出来的,这个表达式是一个桥梁
     */
    private IDCardAbstractExpression cityExp;

    /**
     * 组合终结表达式,最终的判断结果是总结表达式判断出来的,这个表达式是一个桥梁
     */
    private IDCardAbstractExpression typeExp;

    public OrExpression(IDCardAbstractExpression cityExp, IDCardAbstractExpression typeExp) {
        this.cityExp = cityExp;
        this.typeExp = typeExp;
    }

    @Override
    boolean interpret(String expression) {

        return cityExp.interpret(expression)|| typeExp.interpret(expression);
    }
}
package com.dozezz.designpattern.interpreter;

import java.util.HashSet;
import java.util.Set;

/**
 * 环境类
 */
public class AreaContext {

    Set<String> city = new HashSet<>();
    Set<String> type = new HashSet<>();

    /**
     * 读卡器(表达式解释器)
     */
    IDCardAbstractExpression cardAbstractExpression;

    public AreaContext() {

        city.add("北京");
        city.add("天津");
        city.add("河南");

        type.add("PM");
        type.add("PO");
        type.add("程序员");
        TerminalExpression terminalExpression = new TerminalExpression(this.city, ":");
        TerminalExpression terminalExpression1 = new TerminalExpression(this.type, "-");

        cardAbstractExpression = new OrExpression(terminalExpression, terminalExpression1);
    }


    public void getTicket(String expression){
        boolean interpret = cardAbstractExpression.interpret(expression);

        System.out.println(interpret ? "免费吃大餐": "自费吃饭");
    }
}
package com.dozezz.designpattern.interpreter;

/**
 * @Description: 主测试类
 */
public class ClientTest {
    public static void main(String[] args) {
        AreaContext areaContext = new AreaContext();

        areaContext.getTicket("上海:张三-*职业");

        areaContext.getTicket("北京:张三-*职业");
    }
}

三、解释器模式总结

3.1 解释器模式应用场景

  • 当语言的文法较为简单,且执行效率不是关键问题时;
  • 当问题的重复出现,且可以用一种简单的语言来进行表达时;
  • 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候;

3.2 解释器模式注意细节

  • 解释器模式将语法规则抽象的表述为类;
  • 解释器模式为自定义语言的设计和实现提供了一种解决方案,它用于一组文法规则并通过这组文法规则来解释语言中的句子;
  • 解释器模式非常容易扩展,改变和扩展语言的规则非常灵活;
  • 非终结表达式是由终结符表达式构成,基本上需要借助于嵌套、递归、所以代码本身一般比较简单;
  • 解释器中大量的使用递归嵌套,所以说它的性能是很有问题的;

四、参考文献

  • http://c.biancheng.net/view/1376.html
  • https://www.cnblogs.com/noteless/p/10107675.html
  • https://www.bilibili.com/video/BV1G4411c7N4?p=54&spm_id_from=pageDriver
上一篇:Spring中表达式语言spring-expression简单使用


下一篇:设计模式之解释器模式