最近看了刘老师写的设计模式,史上最全设计模式导学目录(完整版)_刘伟技术博客-CSDN博客解释器模式自定义语言的实现——解释器模式(六)_刘伟技术博客-CSDN博客,来做一下老师留的练习题。
练习
Sunny软件公司欲为数据库备份和同步开发一套简单的数据库同步指令,通过指令可以对数据库中的数据和结构进行备份,例如,输入指令“COPY VIEW FROM srcDB TO desDB”表示将数据库srcDB中的所有视图(View)对象都拷贝至数据库desDB;输入指令“MOVE TABLE Student FROM srcDB TO desDB”表示将数据库srcDB中的Student表移动至数据库desDB。试使用解释器模式来设计并实现该数据库同步指令。
首先分析一下指令的内容 :COPY VIEW FROM srcDB TO desDB 。其中一条指令有
COPY 动作,来描述复制还是移动。
VIEW 处理的目标对象可以是表,视图,函数等。后面没有特殊字段表示全部,有的话表示对象名称。
FROM srcDB 原始库。
TO desDB 目标库。
这样得到一条“指令”是由4部分组成,“动作”,“目标对象”,“原始库”,“目标库”组成。由此我们构建对应的class.
先定义指令节点抽象接口。
package com.pattern.explaindb.abs;
import com.pattern.explaindb.Context;
public interface AbstractDbNode {
void interpret(Context context);
String execute();
}
定义上下文对象Context
package com.pattern.explaindb;
import java.util.StringTokenizer;
/**
* 环境类:用于存储和操作需要解释的语句,在本实例中每一个需要解释的单词可以称为一个动作标记(Action Token)或命令
*/
public class Context {
public StringTokenizer tokenizer;
public String currentToken;
public Context(String test) {
tokenizer = new StringTokenizer(test);
nextToken();
}
public String nextToken() {
if(tokenizer.hasMoreTokens()){
currentToken = tokenizer.nextToken();
}else{
currentToken = null;
}
return currentToken;
}
public String currentToken() {
return currentToken;
}
public void skipToken(String token){
if(!token.equals(currentToken)){
System.out.println("错误:" + currentToken + "解释错误!");
}
nextToken();
}
}
分别定义“动作”,
package com.pattern.explaindb;
import com.pattern.explaindb.abs.AbstractDbNode;
/**
* 动作
*/
public class OperateNode implements AbstractDbNode {
private String operate; //动作
private String opname; //动作名称
@Override
public void interpret(Context context) {
operate = context.currentToken();
context.skipToken(operate);
if("COPY".equals(operate)){
opname = "复制";
}else if("MOVE".equals(operate)){
opname = "移动";
}else{
opname = "无法识别命令";
}
}
@Override
public String execute() {
return opname;
}
}
定义:“目标对象”,
package com.pattern.explaindb;
import com.pattern.explaindb.abs.AbstractDbNode;
/**
* 操作目标对象
*/
public class OptionalNode implements AbstractDbNode {
private String option; //操作对象
private String optionname; //操作对象名称
private String target;
@Override
public void interpret(Context context) {
option = context.currentToken();
context.skipToken(option);
//option的类型可以有各种,表,视图,函数,序列,触发器等等。
if("VIEW".equals(option)){
optionname = "视图";
}else if("TABLE".equals(option)){
optionname = "表";
}else if("FUNCTION".equals(option)){
optionname = "函数";
}else{
optionname = "无法识别命令";
}
target = context.currentToken();
if("FROM".equals(target)){
target = "";
}else{
context.skipToken(target);
}
}
@Override
public String execute() {
return optionname + target;
}
}
定义:“库”对象
package com.pattern.explaindb;
import com.pattern.explaindb.abs.AbstractDbNode;
public class DbNode implements AbstractDbNode {
private String dbName;
@Override
public void interpret(Context context) {
String op = context.currentToken();
if("FROM".equals(op) || "TO".equals(op)){
context.skipToken(op);
}
dbName = context.currentToken();
context.skipToken(dbName);
}
@Override
public String execute() {
return dbName;
}
}
然后定义 “指令对象”
package com.pattern.explaindb;
import com.pattern.explaindb.abs.AbstractDbNode;
public class OptionNode implements AbstractDbNode {
private AbstractDbNode operate, optional, fromDb,targetDb; //动作,操作对象,原始库,目标库
@Override
public void interpret(Context context) {
operate = new OperateNode();
operate.interpret(context);
optional = new OptionalNode();
optional.interpret(context);
fromDb = new DbNode();
fromDb.interpret(context);
targetDb = new DbNode();
targetDb.interpret(context);
}
@Override
public String execute() {
return "将数据库" + fromDb.execute() + "中的" + optional.execute() + operate.execute() + "至数据库" + targetDb.execute();
}
}
最后定义一个指令“解释器”:
package com.pattern.explaindb;
import com.pattern.explaindb.abs.AbstractDbNode;
import java.util.ArrayList;
import java.util.List;
public class ExpressionNode implements AbstractDbNode {
private List nodes = new ArrayList<>();
@Override
public void interpret(Context context) {
while (true){
if(context.currentToken() == null){
break;
}else{
AbstractDbNode node = new OptionNode();
node.interpret(context);
nodes.add(node);
}
}
}
@Override
public String execute() {
String result = "";
for (AbstractDbNode node : nodes) {
result += node.execute();
}
return result;
}
}
最后写一个main方法执行一下。
package com.pattern.explaindb;
import com.pattern.explaindb.abs.AbstractDbNode;
public class Client {
public static void main(String[] args) {
//String str = "COPY VIEW FROM srcDB TO desDB";
//String str = "MOVE TABLE Student FROM srcDB TO desDB";
String str = "MOVE FUNCTION Student FROM srcDB TO desDB";
Context context = new Context(str);
AbstractDbNode node = new ExpressionNode();
node.interpret(context);
System.out.println(node.execute());
}
}
执行结果为:
将数据库srcDB中的函数Student移动至数据库desDB
这样就做完了,有改进的地方希望能帮忙指正。感谢!!!!