• 重学设计模式(三、设计模式-解释器模式)


    1、解释器模式

        解释器模式其实就是按照一定的语法去解析的一些方案,可能我们自己去写这样一些解析规则比较少,但是我们平时可能还用的不少。比如,我们使用的正则表达式、EL表达式、数学表达式等等都是解释器的应用。

    1.1、什么是解释器模式

    • 定义

        解释器模式是一种行为设计模式,指给定一种语言,定义其语法的表示形式,以及使用该表示形式来解释该语言中句子。

        解释器模式的结构:

        1)抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret();

        2)终结符表达式(Terminal Expression)角色:实现和语法中末端符号相关的 interpret 方法,语法中的每一个终结符都有一个具体终结表达式与之相对应;

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

        4)环境(Context)角色:用于存储解释器之外的一些全局信息,通常它临时存储需要解释的语句。

       解释器模式的意图在于:让你根据实现定义好的一些语法规则,组合成和执行的对象。

    1.2、解释器模式的优缺点

    • 优点

        扩展性好,在解释器模式中使用类来表示语言的语法规则,因此可以通过继承等机制来改变或扩展语法;

    • 缺点

        1)会引起类膨胀,每条规则至少需要定义一个类,当包含的语法规则很多时,类的个数也会很多,导致系统难以管理与维护;

        2)执行效率问题低,可能在解析规则时使用了大量的循环和递归,效率是一个不容忽视的问题。

    1.3、创建方式

        以中文的数学加减乘除法转阿拉伯数字的加减乘除法为例。

    1)环境(Context)角色

    1. //环境类
    2. public class Context {
    3. Map<String,Integer> dict = new HashMap<String,Integer>();
    4. private String exp;
    5. public Context(String exp){
    6. this.exp = exp;
    7. dict.put("一", 1);
    8. dict.put("二", 2);
    9. dict.put("三", 3);
    10. dict.put("四", 4);
    11. dict.put("五", 5);
    12. dict.put("六", 6);
    13. dict.put("七", 7);
    14. dict.put("八", 8);
    15. dict.put("九", 9);
    16. }
    17. public Map<String, Integer> getDict() {
    18. return dict;
    19. }
    20. public String getExp() {
    21. return exp;
    22. }
    23. public void setExp(String exp) {
    24. this.exp = exp;
    25. }
    26. }

    2)抽象表达式(Abstract Expression)角色

    1. //抽象表达式类
    2. public abstract class AbstractExpression {
    3. public abstract void interpret(Context context);
    4. }

    3)终结符表达式(Terminal Expression)角色

    1. public class TerminalExpression extends AbstractExpression{
    2. @Override
    3. public void interpret(Context context) {
    4. if(context!=null && !"".equals(context.getExp())){
    5. String exp = context.getExp();
    6. for (String str : context.getDict().keySet()) {
    7. if(exp.contains(str)){
    8. Integer s = context.getDict().get(str);
    9. exp = exp.replace(str, s+"");
    10. }
    11. }
    12. context.setExp(exp);
    13. }
    14. }
    15. }

    4)非终结符表达式(Nonterminal Expression)角色

    1. public class NonterminalExpression extends AbstractExpression{
    2. @Override
    3. public void interpret(Context context) {
    4. String exp = context.getExp();
    5. if (exp.contains("加"))
    6. {
    7. exp= exp.replace("加","+");
    8. }
    9. if (exp.contains("减"))
    10. {
    11. exp= exp.replace("减", "-");
    12. }
    13. if (exp.contains("乘"))
    14. {
    15. exp= exp.replace("乘", "*");
    16. }
    17. if (exp.contains("除"))
    18. {
    19. exp= exp.replace("除", "/");
    20. }
    21. context.setExp(exp);
    22. }
    23. }

    5)客户端

    1. public class Client {
    2. public static void main(String[] args) {
    3. Context context = new Context("一加二加三减二乘三除三");
    4. AbstractExpression abstractExpression = new TerminalExpression();
    5. abstractExpression.interpret(context);
    6. AbstractExpression noabstractExpression = new NonterminalExpression();
    7. noabstractExpression.interpret(context);
    8. System.out.println(context.getExp());
    9. }
    10. }
    11. //输出结果:1+2+3-2*3/3

    1.4、总结及建议

        在软件构建过程中,如果某一特定领域的问题比较复杂且类似的情况不断的重复出现,但是使用普通的编程方式来实现可能非常繁琐且不是那么灵活,面临非常频繁的修改,这种情况下使用解释器模式可能会是一种更好的选择。

        其实,以前在开发中也用过这种模式去处理打印数据,将一些打印数据的转换、截取、换行写在配置文件中,用一串规则写在配置文件中作为一种通用的处理(只不过没有按解释器模式这种套路去写的那么规范),实在是处理不了的,才会去单独在代码中重写打印方法去处理打印数据,所以在写代码时设计模式并不是要完全套用的。

    应用场景:

        当一个语言需要解释执行时,并且你可以将该语言中的句子表达为一个抽象的语法树时,可以使用解释器模式。

    JDK中解释器模式的应用:

        java.util.regex.Pattern

  • 相关阅读:
    Java游戏修炼手册:2023 最新学习线路图
    《中学科技》是什么级别的刊物?如何投稿?
    数据库系统概论第一章简答题-期末考得怎么样?
    Linux搭建我的世界MC服务器 【Minecraft外网联机教程】
    从菜鸟到大师:编程必须遵循的三个基本原则
    bp神经网络算法的优缺点,bp神经网络缺点及克服
    pdf怎么转换成word?
    logistic回归模型—基于R
    小波神经网络的基本原理,小波神经网络算法原理
    MongoDB聚合运算符:$cosh
  • 原文地址:https://blog.csdn.net/xiaoxianer321/article/details/125476669