大话设计模式-解释器模式-2020-10-30

定义

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

结构图

image.png

使用场景

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

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

  • 解释器模式可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。

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

音乐解释器的例子

‘O’表示音阶,‘O1’表示低音阶,‘O2’表示中音阶,‘O3’表示高音阶;‘P’表示休止符,‘CDEFGAB’表示‘Do-Re-Mi-Fa-So-La-Ti’;音符长度1表示一拍,2表示2拍,0.5表示半拍,0.25表示四分之一拍,以此类推;注意:所有的字母和数字都要用半角空格分开。例如上海滩的歌曲第一句,‘浪奔’,可以写成‘O 2 E 0.5 G 0.5 A 3 ’表示中音开始,演奏的是mi so la。
T代表速度,以毫秒为单位,‘T1000’表示每节拍一秒,‘T 500’表示没节拍半秒。
为了只关注设计模式编程,而不是具体的播放实现,只需要用控制台根据事先编写的语句解释成简谱就成了。

image.png
  • 结构图
image.png
  • Context
/**
 * 演奏内容
 */
class PlayContext {
    // 演奏文本
    public String playText;
}
  • AbstractExpression
/**
 * 表达式类,AbstractExpression
 */
abstract class Expression {
    // 解释之后的字符串
    protected String result;
    // 供外部获取解释之后的字符串
    public String getResult() {
        return result;
    }

    // 解释器
    public void interpret(PlayContext playContext) {
        if (null != playContext.playText) {
            String playKey = playContext.playText.substring(0, 1);
            playContext.playText = playContext.playText.substring(2);
            double playValue = Double.valueOf(playContext.playText.substring(0, playContext.playText.indexOf(" ")));
            playContext.playText = playContext.playText.substring(playContext.playText.indexOf(" ") + 1);

            execute(playKey, playValue);
        }
    }

    // 执行
    public abstract void execute(String key, double value);
}
  • TerminalExpression
/**
 * 音符类;TerminalExpression
 */
class Note extends Expression {
    @Override
    public void execute(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;
            default:
                // 什么也不做
                break;
        }
        // 保存解释后的结果,供外部访问
        result = note;
    }
}

/**
 * 音阶类;TerminalExpression
 */
class Scale extends Expression {
    @Override
    public void execute(String key, double value) {
        String scale = "";
        switch (Integer.parseInt(new DecimalFormat("0").format(value))) {
            case 1:
                scale = "低音";
                break;
            case 2:
                scale = "中音";
                break;
            case 3:
                scale = "高音";
                break;
            default:
                // 什么也不做
                break;
        }
        // 保存解释后的结果,供外部访问
        result = scale;
    }
}

/**
 * 音速类;TerminalExpression
 */
class Speed extends Expression {
    @Override
    public void execute(String key, double value) {
        String speed = "";
        if (value < 500) {
            speed = "快速";
        } else if (value >= 1000) {
            speed = "慢速";
        } else {
            speed = "中速";
        }
        // 保存解释后的结果,供外部访问
        result = speed;
    }
}
  • 测试界面
image.png
  • 客户端程序
public class InterpreterActivity extends AppCompatActivity {

    public static void launch(Context context) {
        if (null != context) {
            Intent intent = new Intent();
            intent.setClass(context, InterpreterActivity.class);
            if (!(context instanceof Activity)) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            context.startActivity(intent);
        }
    }

    TextView textViewBefore;
    TextView textViewAfter;
    String before;
    String after;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_interpreter);
        setTitle("解释器模式");

        textViewBefore = findViewById(R.id.textViewBefore);
        textViewAfter = findViewById(R.id.textViewAfter);

        interpreter();
    }

    private void interpreter() {
        before = "T 500 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";
        textViewBefore.setText(before);
        after = "";
        PlayContext playContext = new PlayContext();
        playContext.playText = before;
        Expression expression = null;

        try {
            while (playContext.playText.length() > 0) {
                String string = playContext.playText.substring(0, 1);
                switch (string) {
                    case "O":
                        expression = new Scale();
                        break;
                    case "T":
                        expression = new Speed();
                        break;
                    case "C":
                    case "D":
                    case "E":
                    case "F":
                    case "G":
                    case "A":
                    case "B":
                        expression = new Note();
                        break;
                    default:
                        // 什么也不做
                        break;
                }
                if (null != expression) {
                    expression.interpret(playContext);
                    after += expression.getResult() + " ";
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        textViewAfter.setText(after);
    }
}

Demo地址

https://gitee.com/zhangxusong888/Android/tree/master/design_pattern

你可能感兴趣的:(大话设计模式-解释器模式-2020-10-30)