1、 系统设计开发过程
数据库中有“表”的概念。“表”由若干“行”组成,每“行”由许多“列”组成。一般的数据库都提供了对SQL的支持。
我们可以模拟一个最简单版的SQL,只能实现简单的排序,简单的选择条件,列的显示顺序等功能。
输入help会打印出帮助信息。
可以使用下列命令序列测试它:
>load E:\\workspace\\data.txt
>add A 11 22 33 44
>delete A B
>update A length=11 weight=22
>update * A 22 33 44 55
>sort name
>select length weight
>select length weight where price>50
>select * where price>50 length<30
>exit
2、 主要功能模块的实现及调试过程
1. 创建信息类,信息包括名称(String)、长度(double)、重量(double)、威力(double)、price(double)。
class MyRow
{
private String name; // 名字
private double length; // 长度
private double weight; // 重量
private double power; // 威力
private double price; // 价格
public MyRow(String x)
{
String[] ss = x.split(" ");
name = ss[0].trim();
length = Double.parseDouble(ss[1]);
weight = Double.parseDouble(ss[2]);
power = Double.parseDouble(ss[3]);
price = Double.parseDouble(ss[4]);
}
public String toString()
{
return name+" "+length+" "+ weight+" " + power + " " + price;
}
public void SetName(String name){this.name=name;}
public void SetLength(double length){this.length=length;}
public void SetWeight(double weight){this.weight=weight;}
public void SetPower(double power){this.power=power;}
public void SetPrice(double price){this.price=price;}
public String getName() { return name; }
public double getLength() { return length; }
public double getWeight() { return weight; }
public double getPower() { return power; }
public double getPrice() { return price; }
}
2.主类,用来接收用户发送的命令,判断并把命令传给下一级处理类,得到返回值判断命令是否成功执行
public class Test
{
private static BufferedReader br_keyboard;
static
{
// 将它用于从键盘读入
br_keyboard = new BufferedReader(new InputStreamReader(System.in));
}
public static void main(String[] args) throws Exception
{
MyData data = new MyData();
MyCommand cmd = new MyCommand(data); // cmd 服务于 data
for(;;)//一直执行,只能用户用exit命令退出程序
{
System.out.print("请输入命令(输入help显示帮助信息):");
String s = br_keyboard.readLine();
if(s.equals("exit")) break;
if(s.equals("help")){
System.out.println("----------------------------");
System.out.println("1.|load data.txt");
System.out.println(" |从当前目录装入文件data.txt,并显示");
System.out.println("2.|add A 11 22 33 44");
System.out.println(" |增加一条信息(名称A 长度11 重量22 威力33 价格44)到文件中,并显示");
System.out.println("3.|delete A B");
System.out.println(" |删除A和B的信息");
System.out.println("4.|update A length=11 weight=22");
System.out.println(" |把信息A的长度改为11,重量为22");
System.out.println("5.|update * A 22 33 44 55");
System.out.println(" |把信息A的长度、重量、威力、价格 改为22、33、44、55");
System.out.println("6.|sort name");
System.out.println(" |按“名称”排序,并显示");
System.out.println(" |类似地,还可以是 sort length, sort price,sortweight,sort power等");
System.out.println("7.|select length weight");
System.out.println(" |只显示 长度,重量两列");
System.out.println("8.|select length weight where price>50");
System.out.println(" |只显示长度,重量两列, 只包含价格 >50的行");
System.out.println("9.|select * where price>50 length<30");
System.out.println(" |显示所有列, 只包含价格>50 且 长度<30 的行");
System.out.println(" |其它的组合,从上边类推");
System.out.println("0.|exit");
System.out.println(" |退出程序");
System.out.println("----------------------------");
continue;
}
if(!cmd.execute(s)){ //调用下一级类中的函数进行命令的解析
System.out.println("无效的命令");
}
}
}
}
3.命令解析类,把从主类传递过来的命令进行解析,判断命令对应的处理函数,把命令传给对应的函数。接收返回值并返回给Text类。
class MyCommand
{
private MyData data;
public MyCommand(MyData x)
{
data = x;
}
public boolean execute(String x) throws IOException
{
int d = x.indexOf(" "); // 找第一个空格的位置
if(d<0) return false;
String x1 = x.substring(0,d);
String x2 = x.substring(d+1);
if(x1.equals("load")){
if(!data.load(x2.trim()))
System.out.println("装入文件出错!");
return true;
}
if(x1.equals("add"))
return data.add(x2);
if(x1.equals("delete"))
return data.delete(x2);
if(x1.equals("update"))
return data.update(x2);
if(x1.equals("sort"))
return data.sort(x2.trim());
if(x1.equals("select"))
return data.select(x2);
return false;
}
}
4.处理类,处理各种命令,返回处理结果
class MyData
{
// 内部类,“裁判”类,用于裁决Vector中的对象的比较大小问题
class Bijiao implements Comparator<MyRow>
{
private int type; //保存需要比较的信息的序号。例如:1,表示name;2,表示length……
public Bijiao(int type)
{
this.type = type;
}
public int compare(MyRow o1,MyRow o2) //比较的规则
{
if(!(o1 instanceof MyRow)) return 0; //判断传递过来的信息是否是MyRow类
if(!(o2 instanceof MyRow)) return 0;
MyRow r1 = (MyRow)o1;
MyRow r2 = (MyRow)o2;
switch(type){
case 1:
if(r1.equals(r2))
return 0;
else if(r1.getName().compareTo(r2.getName())<0) //name大小排列,小->大
return -1;
else
return 1;
case 2:
if(r1.equals(r2))
return 0;
else if(r1.getLength()<r2.getLength()) //length大小排列,小->大
return -1;
else
return 1;
case 3:
if(r1.equals(r2))
return 0;
else if(r1.getWeight()<r2.getWeight()) //weight大小排列,小->大
return -1;
else
return 1;
case 4:
if(r1.equals(r2))
return 0;
else if(r1.getPower()<r2.getPower()) //power大小排列,小->大
return -1;
else
return 1;
case 5:
if(r1.equals(r2))
return 0;
else if(r1.getPrice()<r2.getPrice()) //price大小排列,小->大
return -1;
else
return 1;
default:
return 0;
}
}
}
private List<MyRow> _v = new Vector<MyRow>(); //保存所有的信息
//在屏幕上显示信息
public void show()
{
System.out.println("....................................");
System.out.println("名称 长度 重量 威力 价格");
for(int i=0; i<_v.size(); i++){
System.out.println(_v.get(i));
}
System.out.println("....................................");
}
File file=null; //全局变量保存路径
//加载文件信息,读取->保存->show()
public boolean load(String x) //x为一个路径
{
try{
if(!x.equals("syh")) //判断加载时否是用户主用命令加载
{
this.file=new File(x);
}
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
_v.clear(); //清空_v,防止二次加载时_v中有之前保存的数据
br.readLine(); // 第一行不要
String s="";
while((s = br.readLine())!=null){
_v.add(new MyRow(s));
}
br.close();
show(); //显示到屏幕
return true;
}
catch(Exception e){
return false;
}
}
//添加信息,先在链表中添加,然后写入文件然后加载
public boolean add(String x) //x:A 11 22 33 44
{
try{
String[] ss = x.split(" ");
String name = ss[0].trim();
x=ss[0]+" "+ss[1]+" "+ss[2]+" "+ss[3]+" "+ss[4];//把数组x改为MyRow()可以分解的数组
if((check(name))==0) //判断添加的信息是否已经存在
{
_v.add(new MyRow(x));
}else{
System.out.println("您增加的信息重复");
return true;
}
Write();
load("syh"); //非用户主动用命令加载信息,读取路径为用户用命令时的路径
return true;
}catch(Exception e){
return false;
}
}
//按name查找某条信息,返回该信息下标+1
public int check(String s)
{
for(int i=0;i<_v.size();i++)
{
MyRow row = (MyRow)_v.get(i);
if(s.equals(row.getName()))
return (i+1); //返回该信息的位置+1是因为防止该信息为下标为0
}
return 0; //信息不存在直接返回0
}
//把信息重新写到文件中
public void Write()
{
try {
Writer out=new FileWriter(file);
out.write("名称 长度 重量 威力 价格");
for(int i=0;i<_v.size();i++)
{
MyRow row = (MyRow)_v.get(i);
out.write("\r\n"+row.getName()+" "+row.getLength()+" "+row.getWeight()+" "+row.getPower()+" "+row.getPrice());
}
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//删除某几条信息,先删除链表中的信息,然后再文件中写入,然后再加载
public boolean delete(String x) //x:A B
{
try{
String[] ss = x.split(" ");
int j;
for(int i=0;i<ss.length;i++)
if((j=check(ss[i]))!=0)
{
_v.remove(j-1);
}
Write();
load("syh");
return true;
}catch(Exception e){
return false;
}
}
//更新信息,先更新链表中的信息->把全部信息写入文件->加载
public boolean update(String x) //x:A length=11 weight=33或者* A 11 22 33 44
{
try {
String ss[]=x.split(" ");
boolean flag=true; //判断更新的信息是否更新,如没更新,则说明该信息不存在
for(int i=1;i<ss.length;i++)
{
String[] ssa=ss[i].split("=");
int j=0;
if((j=check(ss[0]))!=0) //当x为A length=11 weight=33,即部分更新的情况
{
flag=false;
if(ssa[0].equals("length"))
_v.get(j-1).SetLength(Double.parseDouble(ssa[1]));
if(ssa[0].equals("weight"))
_v.get(j-1).SetWeight(Double.parseDouble(ssa[1]));
if(ssa[0].equals("power"))
_v.get(j-1).SetPower(Double.parseDouble(ssa[1]));
if(ssa[0].equals("price"))
_v.get(j-1).SetPrice(Double.parseDouble(ssa[1]));
}
}
if(ss[0].equals("*")) //当x为* A 11 22 33 44,即全部更新情况
{
int j;
if((j=check(ss[1]))!=0)
{
flag=false;
_v.get(j-1).SetLength(Double.parseDouble(ss[2]));
_v.get(j-1).SetWeight(Double.parseDouble(ss[3]));
_v.get(j-1).SetPower(Double.parseDouble(ss[4]));
_v.get(j-1).SetPrice(Double.parseDouble(ss[5]));
}
}
if(flag)
{
System.out.println("不存在您要更新的内容");
return true;
}
Write();
load("syh");
return true;
}catch (Exception e) {
return false;
}
}
//排序
public boolean sort(String x) //x可为name或者lengt或者weight……
{
if(x.equals("name")){
Collections.sort(_v, new Bijiao(1)); //1表示名称,类似2为长度……
show();
return true;
}
if(x.equals("length")){
Collections.sort(_v, new Bijiao(2));
show();
return true;
}
if(x.equals("weight")){
Collections.sort(_v, new Bijiao(3));
show();
return true;
}
if(x.equals("power")){
Collections.sort(_v, new Bijiao(4));
show();
return true;
}
if(x.equals("price")){
Collections.sort(_v, new Bijiao(5));
show();
return true;
}
return false;
}
// 筛选需要显示的信息,把筛选命令分解
public boolean select(String x) //x:select weight length或者select weight length where price>50或者 select * where price>50 length<30
{
Vector<String> sort = new Vector<String>(); // 保存需要显示的信息
Vector<String> where = new Vector<String>(); // 保存过滤的条件即where后面的字符
String[] ss = x.split(" ");
Vector<String > t = sort;
for(int i=0; i<ss.length; i++){
if(ss[i].length()==0) continue; // 防止多个空格
if(ss[i].equals("where")){
t = where;
continue;
}
t.add(ss[i]);
}
if(sort.size()==0) return false; // 字段必须指定
if(sort.size()>5) return false; // 字段太多
return select(sort, where);
}
// 执行select任务
public boolean select(Vector<String> sort,Vector<String> where)
{
try{
System.out.println("....................................");
//输出标题
System.out.print("名称 ");
for(int k=0; k<sort.size(); k++){ // 枚举sort
if(sort.get(k).equals("length"))
System.out.print("长度 ");
else if(sort.get(k).equals("weight"))
System.out.print("重量 ");
else if(sort.get(k).equals("power"))
System.out.print("威力 ");
else if(sort.get(k).equals("price"))
System.out.print("价格 ");
else if(sort.get(k).equals("*"))
System.out.print("长度 重量 威力 价格 ");
else
return false;
}
System.out.println("");
for(int i=0; i<_v.size(); i++){ //输出内容
MyRow row = (MyRow)_v.get(i);
if(checkWhere(row, where)){
System.out.print(row.getName() + " ");
for(int k=0; k<sort.size(); k++){
if(sort.get(k).equals("length"))
System.out.print(row.getLength() + " ");
else if(sort.get(k).equals("weight"))
System.out.print(row.getWeight() + " ");
else if(sort.get(k).equals("power"))
System.out.print(row.getPower() + " ");
else if(sort.get(k).equals("price"))
System.out.print(row.getPrice() + " ");
else if(sort.get(k).equals("*"))
System.out.print(row.getLength()+" "+row.getWeight()+" "+row.getPower()+" "+row.getPrice());
else
return false;
}
System.out.println("");
}
}
System.out.println("....................................");
return true;
}
catch(Exception e){
//e.printStackTrace();
return false;
}
}
// 返回true 则该行记录显示,返回false,则不显示
public boolean checkWhere(MyRow row, Vector<String > where) throws Exception
{
boolean op=true; // true: 表示比较符号为 > , 否则为 <
String field = ""; // 过滤条件的字段
String value = ""; // 过滤值
// 对每一个条件处理
for(int i=0; i<where.size(); i++){
String s = (String)where.get(i);
String[] ss = s.split(">");
if(ss.length==2){
field = ss[0];
op = true;
value = ss[1];
}
else{
ss = s.split("<");
if(ss.length==2){
field = ss[0];
op = false;
value = ss[1];
}
else
return false; // 既没有"<"也没有">"的情况
}
double d_value = Double.parseDouble(value);
if(field.equals("length")){
if(op){
if(row.getLength() <= d_value) return false;
}
else{
if(row.getLength() >= d_value) return false;
}
}
else if(field.equals("weight")){
if(op){
if(row.getWeight() <= d_value) return false;
}
else{
if(row.getWeight() >= d_value) return false;
}
}
else if(field.equals("power")){
if(op){
if(row.getPower() <= d_value) return false;
}
else{
if(row.getPower() >= d_value) return false;
}
}
else if(field.equals("price")){
if(op){
if(row.getPrice() <= d_value) return false;
}
else{
if(row.getPrice() >= d_value) return false;
}
}
else
throw new Exception("valid field name!"); // 无法识别的 field,则算错表达式错
}
return true;
}
}
3、 系统存在的不足
在对数据进行增(add)、删(delete)、改(update)时,先对从文件读取的数据进行修改,然后重新写入文件然后再读取显示到屏幕中。这种操作在数据量较小时处理的时间比较短,但随着数据量的增加处理的时间就会急剧增加,假如修改一个数据需要时间为x,往文件中写入一个数据需要时间为y,从文件中读取一个数据时间为z,则增加一条数据则用时为:(x+(n+1)*y+(n+1)*z)。若直接在文件中进行增加一条数据则用时为:(y+(n+1)*z)。这样比较就显示出程序的效率太低,需要改进。还有就是只能对特定的表进行操作,比如如果表的属性不是 名称(String)、长度(double)、重量(double)、威力(double)、price(double),则功能就不能实现,但是该缺点易改进,使用Map进行匹配就可以实现对任意表进行操作。源码 下载地址