解释器模式练习-数据库备份

 最近看了刘老师写的设计模式,史上最全设计模式导学目录(完整版)_刘伟技术博客-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<AbstractDbNode> 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

这样就做完了,有改进的地方希望能帮忙指正。感谢!!!!

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值