大话设计模式读书笔记——解释器模式


1. 解释器模式

1.1 概念

解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

1.2 应用场景

如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。如正则表达式匹配。

1.3 案例代码

1.3.1 UML类图

在这里插入图片描述

1.3.2 抽象表达式类

AbstractExpression(抽象表达式),声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。

public abstract class AbstractExpression {
    //解释操作
    public abstract void interpret(Context context);
}

1.3.3 终结符表达式类

TerminalExpression(终结符表达式),实现与文法中的终结符相关联的解释操作。实现抽象表达式中所要求的接口,主要是一个interpret()方法。文法中每一个终结符都有一个具体终结表达式与之相对应。

public class TerminalExpression extends AbstractExpression{
    @Override
    public void interpret(Context context) {
        System.out.println("终端解释器");
    }
}

1.3.4 非终结符表达式类

NonterminalExpression(非终结符表达式),为文法中的非终结符实现解释操作。对文法中每一条规则R1、R2、…、Rn都需要一个具体的非终结符表达式类。通过实现抽象表达式的interpret()方法实现解释操作。解释操作以递归方式调用上面所提到的代表R1、R2、…、Rn中各个符号的实例变量。

public class NonterminalExpression extends AbstractExpression{
    @Override
    public void interpret(Context context) {
        System.out.println("非终端解释器");
    }
}

1.3.5 Context类

Context,包含解释器之外的一些全局信息。

public class Context {
    private String input;
    private String output;

    public String getInput() {
        return input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public String getOutput() {
        return output;
    }

    public void setOutput(String output) {
        this.output = output;
    }
}

1.3.5 客户端代码

    Context context = new Context();
    ArrayList<AbstractExpression> list = new ArrayList<>();
    list.add(new TerminalExpression());
    list.add(new NonterminalExpression());
    list.add(new TerminalExpression());
    list.add(new TerminalExpression());

    for (AbstractExpression exp : list) {
        exp.interpret(context);
    }

1.3.6 输出结果

终端解释器
非终端解释器
终端解释器
终端解释器

1.4 优点与不足

解释器模式容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。
但解释器也存在着不足:解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。

2. 需求

尝试用代码实现一个音乐解释器。
规则:是O表示音阶’O 1’表示低音阶,'O 2’表示中音阶,'O 3’表示高音阶;'P’表示休止符,‘C D E F G A B’表示’Do-Re-Mi-Fa-So-La-Ti’;音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍,以此类推。注意:所有的字母和数字都要用半角空格分开。例如上海滩的歌曲第一句,‘浪奔’,可以写成’O 2 E 0.5 G 0.5 A 3’表示中音开始,演奏的是mi so la。

3. 代码版本1.0

3.1 UML类图

在这里插入图片描述

3.2 演奏内容类

public class PlayContext {
    private String playText;

    public String getPlayText() {
        return playText;
    }

    public void setPlayText(String playText) {
        this.playText = playText;
    }
}

3.3 表达式类

public abstract class Expression {
    public void interpret(PlayContext context){
        if (context.getPlayText().length()==0){
            return;
        }else{
            String playKey = context.getPlayText().substring(0, 1);
            context.setPlayText(context.getPlayText().substring(2));

            double playValue = Double.parseDouble(context.getPlayText().substring(0,context.getPlayText().indexOf(" ")));
            context.setPlayText(context.getPlayText().substring(context.getPlayText().indexOf(" ")+1));
            this.excute(playKey,playValue);
        }
    }

    //抽象方法执行,不同的文法子类有不同的执行处理
    public abstract void excute(String key,double value);
}

3.4 音符类

public class Note extends Expression{
    @Override
    public void excute(String key, double value) {
        String note = "";
        switch (key){
            case "C":
                note = "1";
                break;
            case "D":
                note = "2";
                break;
            case "E":
                note = "3";
                break;
            case "F":
                note = "4";
                break;
            case "G":
                note = "5";
                break;
            case "A":
                note = "6";
                break;
            case "B":
                note = "7";
                break;
        }
        System.out.print(note+" ");
    }
}

3.5 音阶类

public class Scale extends Expression{
    @Override
    public void excute(String key, double value) {
        String scale = "";
        switch ((int)value){
            case 1:
                scale = "低音";
                break;
            case 2:
                scale = "中音";
                break;
            case 3:
                scale = "高音";
                break;
        }
        System.out.print(scale+" ");
    }
}

3.6 客户端代码

     PlayContext context = new PlayContext();
     System.out.println("音乐——上海滩");
     context.setPlayText("0 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 0 3 C 1 0 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ");
     Expression expression = null;

     while(context.getPlayText().length()>0){
         String str = context.getPlayText().substring(0, 1);
         switch (str){
             case "0":
                 expression = new Scale();
                 break;
             case "C":
             case "D":
             case "E":
             case "F":
             case "G":
             case "A":
             case "B":
             case "P":
                 expression = new Note();
                 break;
         }
         expression.interpret(context);
     }

3.7 输出结果

音乐——上海滩
中音 3 5 6 3 5 2 3 5 6 高音 1 中音 6 5 1 3 2 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头盔程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值