解释器模式


23种设计模式

1.什么是解释器模式

遇到需求经常变化的项目,直接用Java语言实现,然后每更改一次需求,就修改相应的源代码?
这样的做法是非常不明智的。
好一些的程序会把经常变化的部分作为可配置的,这样需要修改哪些部分,只需要修改配置文件即可。
但是如果我们需要修改的这部分不是静态的,或者说无法用静态的语言描述,甚至描述非常的困难时,配置文件的方法就力所不及了。
那么,该怎么办?

牛逼的人会创一套专门用于解决这部分问题的编程语言,这也是为什么有那么多的编程语言的一部分原因。
比如 :
程序员英文不好,那么就有了用中文编程的编程语言–易语言
普通编程语言对于数学,比如矩阵的加减乘除,点乘,叉乘等的支持不好,因为运算规则确定,却没有专门的支持,于是就有了—MATLAB,lingo等等
介绍一个新语言:Groovy语言,这个语言与Java无缝结合。

像我们一般玩家怎么办呢,就是使用封装在基本语言的上层的语言。
这里把一些功能强大,使用非常普遍的编程语言理解为基本语言。

但是遇到某个问题,我们既没有牛逼人物的牛逼能力,又找不到合适的封装语言,那该怎么办呢?

解释器模式。

2.核心思想

对于一些固定的操作进行封装,然后定义一套自己的规则。
然后在规则之上进行开发。

因为是封装,所以在规则之上的工作量远远小于没有封装的工作量(一般情况,除非封装是专门把操作复杂化)

这样每次改动的内容就比较少。

说白了就是自己顶一个语法规则,然后自己玩。。。。。。。

3.例子

3.1 背景

在面板上画线,按照4个方位。
要求:根据输入,实时画线。

3.2 分析

背景很简单,要求更简单。。。。
但是分析不简单:
首先画一条线,画多长?
怎么画?横着,竖着?
画一条?
两条?
画线的人如何交互?按钮?键盘?
实时响应?
错误输入怎么办?画无线长?
。。。。。

3.3 画界面

23种设计模式----解释器模式----行为型模式_23种设计模式


效果图:

23种设计模式----解释器模式----行为型模式_Java图形界面输入实时获取_02

3.4 代码实现

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;


public class Main {

/**
* 根窗口容器
*/
private JFrame jFrame;

/**
* 当前线段的起点x
*/
private int xnow;

/**
* 当前线段的起点y
*/
private int ynow;

/**
* 构造方法
*/
public Main(){
jFrame = new JFrame();
init();
//显示窗体
jFrame.setVisible(true);
}

/**
* 抽取初始化方法
*/
private void init(){
//窗口的标题
jFrame.setTitle("23种设计模式----解释器模式");
//使用绝对布局
jFrame.setLayout(null);
//设置大小
jFrame.setSize(800, 800);
//设置初始居中
jFrame.setLocationRelativeTo(null);
//设置不可最大化,不可拖动大小
jFrame.setResizable(false);
//设置默认关闭方式(有时可能是假关闭)
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//黄色面板
JPanel topPanel = new JPanel();
//设置背景色
topPanel.setBackground(Color.YELLOW);
//设置黄色面板大小
topPanel.setSize(jFrame.getSize().width, jFrame.getSize().height/2);
//设置黄色面板中点为初始点
xnow = jFrame.getSize().width/2;
//设置黄色面板中点为初始点
ynow = jFrame.getSize().height/4;
//绿色面板
JPanel botPanel = new JPanel();
//绿色面板背景
botPanel.setBackground(Color.GREEN);
//设置绿色面板大小
botPanel.setSize(jFrame.getSize().width, jFrame.getSize().height/2);
//设置绿色面板位置(从哪里开始画)
botPanel.setLocation(0, jFrame.getSize().height/2);
//增加文本区控件
botPanel.add(getJTextArea());
//把面板加到窗体中
jFrame.add(topPanel);
jFrame.add(botPanel);
//为窗口增加监听方法
addJFrameCloseListener();
}

private JTextArea getJTextArea(){
JTextArea textArea = new JTextArea();
//设置文本区的大小
textArea.setSize(jFrame.getSize().width, jFrame.getSize().height/2);
//设置文本区自动换行(一行满了换下一行)
textArea.setLineWrap(true);
//设置按字符换行(比如每一个字符或者单词的长短不一,不分割字符或者单词进行换行)
textArea.setWrapStyleWord(true);
//设置文本区域的背景色
textArea.setBackground(Color.GREEN);
//设置文本区域文字的颜色
textArea.setForeground(Color.BLUE);
//设置文本区域文字的字体(大小,风格,字体)
textArea.setFont(getFont());
//为文本区域增加监听
addTextAreaListener(textArea);
return textArea;
}

private Font getFont(){
//创建楷体,实线,23大小的字体
Font font = new Font("楷体", Font.BOLD, 23);
return font;
}

private void addJFrameCloseListener(){
//增加窗体监听
jFrame.addWindowListener(new WindowAdapter() {
//监听关闭事件
@Override
public void windowClosed(WindowEvent e){
//当窗体关闭后,程序进程也结束
System.exit(0);
}
});
}

private void addTextAreaListener(final JTextArea textArea){
//增加文本区的监听
textArea.getDocument().addDocumentListener(new DocumentListener() {

//文本区文本被移除
@Override
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}

//文本区文本插入
@Override
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}

//文本区文本改变
@Override
public void changedUpdate(DocumentEvent e) {
char c = textArea.getText().charAt(e.getOffset());
System.out.println(c);
draw(c);
}
});
}

private void draw(char c){
//获取画图的对象
Graphics graphics = jFrame.getGraphics();
//转换为专门画2d图的对象
Graphics2D graphics2d = (Graphics2D)graphics;
//设置画图的线的宽度
graphics2d.setStroke(new BasicStroke(5.0f));
//设置画图的线的颜色
graphics2d.setColor(Color.PINK);
//设置画图的字体
graphics2d.setFont(getFont());
//将要画的线段的结束端与开始端相同(点---起点)
int xnext = xnow;
int ynext = ynow;
switch(c){
//东
case 'W':
case 'w':
xnext = xnow + 10;
break;
//南
case 'S':
case 's':
ynext = ynow + 10;
break;
//西
case 'E':
case 'e':
xnext = xnow - 10;
break;
//北
case 'N':
case 'n':
ynext = ynow - 10;
break;
//其他
default:
xnext = xnow;
ynext = ynow;
break;
}
//超出边界的值设置为边界
xnext = xnext > jFrame.getSize().width ? jFrame.getSize().width : xnext;
ynext = ynext > jFrame.getSize().height/2 ? jFrame.getSize().height/2 : ynext;
xnext = xnext < 0 ? 0 : xnext;
ynext = ynext < 0 ? 0 : ynext;
//按照起点和终点画线
graphics2d.drawLine(xnow, ynow, xnext, ynext);
//把本次线段的终点设置为下一次线段的起点
xnow = xnext;
ynow = ynext;
}

public static void main(String[] args) {
new Main();
}

}

3.5 效果

画一个1单位长度的正方形:

23种设计模式----解释器模式----行为型模式_Java画图_03


2单位长度的正方形:

23种设计模式----解释器模式----行为型模式_Java画图_04


画台阶

23种设计模式----解释器模式----行为型模式_Java图形界面输入实时获取_05

4.总结

看上去挺简单的,但是只要不断的扩充,一定能够实现更复杂的程序。
比如我们的程序能够读取每一个字符,并在控制台回写,那么,所有的文本编辑器,与这个有什么区别呢?

能不能设置一个定时器,定时器里面有相应的画图的代码或者命令,实现动画功能?

能不能实现一些简单的小游戏呢?用解释器模式实现的小游戏,游戏规则是不是可以实时更改呢????