为了账号安全,请及时绑定邮箱和手机立即绑定

java设计模式--解释器模式

标签:
Java 设计

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

解释器模式解决的是—如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
图片描述
其中的终结符表达式 和非终结符表达式可以理解为:公式R=R1+R2中,R1、R2为终结符表达式,+为非终结表达式(其后需要跟随一个终结符表达式)。

各个角色的代码----
AbstractExpression(抽象表达式),声明一个抽象的解释操作,这个接口作为抽象语法树中所有节点(即终结符表达式和非终结符表达式)所共享:

package com.design.interpreter;

public abstract class AbstractExpression {
    public abstract void interpret(Context context);
}

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

package com.design.interpreter;

public class TerminalExpression extends AbstractExpression{

    @Override
    public void interpret(Context context) {
        System.out.println("終結符解释器");
    }

}

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

package com.design.interpreter;

public class NonterminalExpression extends AbstractExpression{

    @Override
    public void interpret(Context context) {
        System.out.println("非終結符解释器");
    }

}

Context类(包含解释器之外的一些全局信息):

package com.design.interpreter;

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

    Get&Set方法略… 
}

客户端,构建表示该文法定义的语言中一个特定的句子抽象语法数,调用解释器操作:

package com.design.interpreter;

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        Context context = new Context();
        List<AbstractExpression> list = new ArrayList<AbstractExpression>();
        list.add(new TerminalExpression());
        list.add(new NonterminalExpression());
        list.add(new TerminalExpression());
        list.add(new NonterminalExpression());
        for (AbstractExpression abstractExpression : list) {
            abstractExpression.interpret(context);
        }
    }
}

当有一个语言需要解释执行,并且你可以将改语言中的句子表示为一个抽象语法树时,可以使用解释器模式。
有了解释器模式,可以很容易的改变和拓展文法,因为该模式使用类来表示文法规则,可以使用继承来改变或者拓展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类大体相似,这些类都易于直接编写。

解释器模式的缺点:为文法中每一条规则至少定义了一个类,因为包含了许多规则的文法可能难于维护和管理,建议当文法十分复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。

以手机编辑铃声为例:
首先制定规则,S代表速度,500低速,1000中速,1500高速,O代表音阶,‘O 1’代表低音阶,‘O 2’代表中音阶,‘O 3’代表高音阶,‘P’代表休止符,‘CDEFGAB’代表音调,1表示一拍,0.5表示半拍,依此类推。所有的字母和数字使用空格分隔。例:“O 2 E 0.5 G 0.5 A 3 E 0.5”
图片描述
演奏内容类Context:

package com.design.interpret;

public class Context {
    //演奏文本
    private String playText ;  

    public String getPlayText() {
        return playText;
    }

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

}

表达式类AbstractExpression:

package com.design.interpret;

public abstract class AbstractExpression {  
    //将演奏文本解析为对应的key和value,根据key值指定解释器
    public void interpret(Context context){
        if(context.getPlayText().length()==0){
            return;
        }
        //获取文本第一个字符作为key值
        String playText = context.getPlayText();
        String key = playText.substring(0,1);
        //获取key值后截取文本
        playText = playText.substring(2);
        //获取截取后文本第一个字段作为value值
        Double value = Double.parseDouble(playText.substring(0,playText.indexOf(" ")));
        //获取value值后截取文本
        playText = playText.substring(playText.indexOf(" ")+1);
        context.setPlayText(playText);
        //解释器执行
        excute(key, value);
    };   

    public abstract void excute(String key, Double value);
}  

音符类NoteExpression:

package com.design.interpret;

public class NoteExpression extends AbstractExpression {  

    @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+" ");
    }  
}  

音调类ScaleExpression:

package com.design.interpret;

public class ScaleExpression extends AbstractExpression {

    @Override
    public void excute(String key, Double value) {
        String scale = "";
        switch (value.intValue()) {
        case 1:
            scale = "low";
            break;
        case 2:
            scale = "middle";
            break;
        case 3:
            scale = "high";
            break;
        }
        System.out.print(scale+" ");
    }  

}

音速类SpeedExpression:

package com.design.interpret;

/**
 * 音速类
 * @author hydra
 *
 */
public class SpeedExpression extends AbstractExpression {

    @Override
    public void excute(String key, Double value) {
        String speed = "";
        switch (value.intValue()) {
        case 500:
            speed = "slow";
            break;
        case 1000:
            speed = "middle";
            break;
        case 1500:
            speed = "fast";
            break;
        }
        System.out.print(speed+" ");
    }

}

因为解释器会不断重复使用,所以这里用到了享元模式来生成各种具体的解释器:

package com.design.interpret;

import java.util.Hashtable;

public class ExpressionFactory {

    //使用hashtable变量储存编译器列表
    private static Hashtable<Object, AbstractExpression> expressions = new Hashtable<Object, AbstractExpression>();

    public static AbstractExpression createExpression(String text) {

        String key = text.substring(0,1);
        AbstractExpression expression = null;
        switch (key) {
        case "C":
        case "D":
        case "E":
        case "F":
        case "G":
        case "A":
        case "B":
            expression = expressions.get("note");
            if (expression == null) {
                expression = new NoteExpression();
                expressions.put("note", expression);
            }
            break;
        case "O":
            expression = expressions.get("scale");
            if (expression == null) {
                expression = new ScaleExpression();
                expressions.put("scale", expression);
            }
            break;
        case "S":
            expression = expressions.get("speed");
            if (expression == null) {
                expression = new SpeedExpression();
                expressions.put("speed", expression);
            }
            break;
        }
        //System.out.println(expressions.size());
        return expression;
    }
}

客户端演奏:

package com.design.interpret;

public class Client {  

    /** 
     * @param args 
     */  
    public static void main(String[] args) {
        Context context = new Context() ;  
        //设置演奏文本
        context.setPlayText("S 1500 O 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 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ");
        AbstractExpression expression = null;
        try {
            while (context.getPlayText().length()>0) {
                //使用享元模式
                expression = ExpressionFactory.createExpression(context.getPlayText());
                expression.interpret(context);
            }
        } catch (Exception e) {
        }
    }  

}  

演奏结果:

图片描述

以上。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
27
获赞与收藏
233

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消