【更新】
2012-6-3
更新【代码重构】
2012-6-2
(1) 修复getDataByIndex、getDataByName潜在bug
(2) 添加代码重构栏目,后续更新将补充完整
【问题描述】在JavaMe 编程连载(7) - 数据永久存储一文结尾,提到了构建通用数据库的思路。最近,在阅读《重构-改善既有代码的设计》,感觉刚开始写的数据永久存储代码比较丑陋。一时技痒。写了一个通用的数据永久存储。分享一下代码和思路。
【代码清单】
原来的代码就不列了,详细请参考JavaMe 编程连载(7) - 数据永久存储一文。
DataItem.java(update:2012-6-2)
package com.token.model; import com.token.util.StringMethod; public class DataItem { private int id; private String args_t[][]; private Object[] args; private int length; public DataItem(int id, Object[] args) { this.id = id; this.args = args; length = args.length; args_t = new String[args.length][2]; for (int i = 0; i < args.length; i++) { args_t[i] = StringMethod.split((String) args[i], "="); // System.out.println(args_t[i][0]); // System.out.println(args_t[i][1]); } } public DataItem(int id, String data) { // System.out.println(data); String temp[] = StringMethod.split(data, ","); this.id = id; this.args = temp; length = temp.length; args_t = new String[temp.length][2]; for (int i = 0; i < temp.length; i++) { args_t[i] = StringMethod.split(temp[i], "="); // System.out.println(args_t[i][0]); // System.out.println(args_t[i][1]); } } public DataItem(int id, byte[] record) { // TODO Auto-generated constructor stub this.id = id; String temp = new String(record); System.out.println(temp); } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getDataLength() { return length; } public String getDataByIndex(int index) { if(index<getDataLength()) { return args_t[index][1]; } else { return ""; } } public String getDataByName(String name) { int index = -1; int i; for (i = 0; i < getDataLength(); i++) { if (args_t[i][0].equals(name)) { index = i; break; } } if(index != -1) { return args_t[index][1]; } else { return ""; } } public byte[] getBytes() { String data = ""; for (int i = 0; i < args.length; i++) { data += (String) args[i]; data += ","; } data = data.substring(0, data.length() - 1); // System.out.println(data); return data.getBytes(); } }
DataRecord.java
package com.token.util; import java.util.Vector; import javax.microedition.rms.RecordComparator; import javax.microedition.rms.RecordEnumeration; import javax.microedition.rms.RecordStore; import javax.microedition.rms.RecordStoreException; import com.token.model.DataItem; public class DataRecord { private RecordStore record; private String dataBaseName; public DataRecord(String name) { dataBaseName = name; } protected String getDataBaseName() { // System.out.println(dataBaseName); return dataBaseName; } // 打开RecordStore public void openDataBase() { String name = getDataBaseName(); try { record = RecordStore.openRecordStore(name, true); } catch (RecordStoreException ex) { record = null; System.out.println(ex); } } // 关闭RecordStore public void closeDataBase() { if (record != null) { try { record.closeRecordStore(); record = null; } catch (RecordStoreException ex) { System.out.println(ex); } } } // 增加记录 public int db_addRecord(DataItem item) { try { this.openDataBase(); byte[] data = item.getBytes(); int id = record.getNextRecordID(); record.addRecord(data, 0, data.length); this.closeDataBase(); return id; } catch (RecordStoreException ex) { System.out.println(ex); } return -1; } // 更新记录 public void db_updateRecord(DataItem item) { try { this.openDataBase(); byte[] data = item.getBytes(); record.setRecord(item.getId(), data, 0, data.length); this.closeDataBase(); } catch (RecordStoreException ex) { System.out.println(ex); } } // 访问一条记录 public DataItem db_getRecord(int id) { DataItem item = null; try { this.openDataBase(); byte data[] = record.getRecord(id); item = new DataItem(id, new String(data)); this.closeDataBase(); } catch (RecordStoreException ex) { // System.out.println(ex); } return item; } // 删除一条记录 public void db_deleteRecord(int id) { try { this.openDataBase(); record.deleteRecord(id); this.closeDataBase(); } catch (RecordStoreException ex) { System.out.println(ex); } } // 删除所有记录 public void db_deleteAllRecord() { try { RecordStore.deleteRecordStore(getDataBaseName()); } catch (RecordStoreException ex) { System.out.println(ex); } } // 访问所有记录 public Vector db_getRecords() { Vector items = new Vector(10, 3); this.openDataBase();// 打开RecordStore RecordEnumeration enum1 = null; int ind = 0; try { DataItem item = null; enum1 = record.enumerateRecords(null, new InnerComparator(), false); while (enum1.hasPreviousElement()) { ind = enum1.previousRecordId(); item = new DataItem(ind, record.getRecord(ind)); items.addElement(item); } } catch (Exception ex) { ex.printStackTrace(); } finally { try { enum1.destroy(); } catch (Exception e) { } this.closeDataBase();// 关闭RecordStore }// end finally return items; } // 一个简单的比较器 private class InnerComparator implements RecordComparator { public int compare(byte[] rec1, byte[] rec2) { if (rec1.length > rec2.length) return FOLLOWS; else if (rec1.length < rec2.length) return PRECEDES; else return EQUIVALENT; } } public static class DataBaseName { public static final String DB_TEST = "test"; } }
StringMethod.java
package com.token.util; import java.util.Vector; import javax.microedition.lcdui.Font; public class StringMethod { StringMethod() { } // 字符串切割,实现字符串自动换行 public static String[] format(String text, int maxWidth, Font ft) { String[] result = null; Vector tempR = new Vector(); int lines = 0; int len = text.length(); int index0 = 0; int index1 = 0; boolean wrap; while (true) { int widthes = 0; wrap = false; for (index0 = index1; index1 < len; index1++) { if (text.charAt(index1) == '\n') { index1++; wrap = true; break; } widthes = ft.charWidth(text.charAt(index1)) + widthes; if (widthes > maxWidth) { break; } } lines++; if (wrap) { tempR.addElement(text.substring(index0, index1 - 1)); } else { tempR.addElement(text.substring(index0, index1)); } if (index1 >= len) { break; } } result = new String[lines]; tempR.copyInto(result); return result; } public static String[] split(String original, String separator) { Vector nodes = new Vector(); // System.out.println("split start..................."); // Parse nodes into vector int index = original.indexOf(separator); while (index >= 0) { nodes.addElement(original.substring(0, index)); original = original.substring(index + separator.length()); index = original.indexOf(separator); } // Get the last node nodes.addElement(original); // Create splitted string array String[] result = new String[nodes.size()]; if (nodes.size() > 0) { for (int loop = 0; loop < nodes.size(); loop++) { result[loop] = (String) nodes.elementAt(loop); // System.out.println(result[loop]); } } return result; } }
测试代码(update:2012-6-2)
public void test() { DataRecord record = new DataRecord("test"); //DataRecord record = new DataRecord(DataRecord.DataBaseName.DB_TEST); // delete all record.db_deleteAllRecord(); // add DataItem item1 = new DataItem(1, "name=zhang,x=1,y=2,z=3"); int id = record.db_addRecord(item1); System.out.println("id:"+id); DataItem item = record.db_getRecord(id); System.out.println("z:" + item.getDataByName("z") + "(getbyname)"); System.out.println("y:" + item.getDataByIndex(2) + "(getbyindex)"); System.out.println("test u:" + item.getDataByName("u") + "(getbyname)");//越界 System.out.println("test:" + item.getDataByIndex(4) + "(getbyindex)");//越界 // add Object[] data1 = { "name=liu,x=4,y=5,z=6" }; DataItem item2 = new DataItem(1, data1); id = record.db_addRecord(item2); System.out.println("id:"+id); record.db_getRecords(); // update Object[] data2 = { "name=li,x=7,y=8,z=9" }; DataItem item3 = new DataItem(id, data2); record.db_updateRecord(item3); item = record.db_getRecord(id); System.out.println("x:" + item.getDataByName("x")); // delete record.db_deleteRecord(id); record.db_getRecords(); }
【分析】
1 该通用数据永久存储提供了两种数据格式:
(1) 传递Object []对象
Object[] data2 = { "name=li,x=7,y=8,z=9" }; DataItem item3 = new DataItem(id, data2);
(2) 传递String
DataItem item1 = new DataItem(1, "name=zhang,x=1,y=2,z=3");
数据采用key=value的形式进行存储,以“,”分隔键值对。
2 实现了增、改、删、查
(1) 增
DataItem item1 = new DataItem(1, "name=zhang,x=1,y=2,z=3"); int id = record.db_addRecord(item1);
(2) 改
Object[] data2 = { "name=li,x=7,y=8,z=9" }; DataItem item3 = new DataItem(id, data2); record.db_updateRecord(item3);
(3) 删
delete all
record.db_deleteAllRecord();
delete by id
record.db_deleteRecord(id);
(4) 查
get all
record.db_getRecords();
get record by id
DataItem item = record.db_getRecord(id); System.out.println("x:" + item.getDataByName("x") + "(getbyname)"); System.out.println("y:" + item.getDataByIndex(2) + "(getbyindex)");
3 提供了两种数据访问方式
(1) 按键(key)访问
System.out.println("x:" + item.getDataByName("x") + "(getbyname)");
(2) 按索引访问
*第1个数据索引为0,依次类推
System.out.println("y:" + item.getDataByIndex(2) + "(getbyindex)");
4 如何使用
在构造对象时,传入记录名作为区分,该名称为记录唯一标识,提供访问记录接口
DataRecord record = new DataRecord("test");
为了在不同文件中使用,防止出错,在DataRecord.java中建了一个内部类,存储记录名
public static class DataBaseName { public static final String DB_TEST = "test"; }
每次调用可采用如下方式:
DataRecord record = new DataRecord(DataRecord.DataBaseName.DB_TEST);
5 拓展
可以将DataItem和DataRecord做为基类,采用装饰模式,进行包装,使用更简便。
【代码重构】(2012-6-2)
1 去掉分支结构
在代码清单中,下面一段还是比较丑陋
public String getDataByIndex(int index) { if(index<getDataLength()) { return args_t[index][1]; } else { return ""; } } public String getDataByName(String name) { int index = -1; int i; for (i = 0; i < getDataLength(); i++) { if (args_t[i][0].equals(name)) { index = i; break; } } if(index != -1) { return args_t[index][1]; } else { return ""; } }
运用去除分支结构的方法,重构后,
public String getDataByIndex(int index) { //System.out.println(index); return index < getDataLength() ? args_t[index][1] : ""; } public String getDataByName(String name) { int index = -1; int i; for (i = 0; i < getDataLength(); i++) { if (args_t[i][0].equals(name)) { index = i; break; } } //System.out.println(index); return index != -1 ? args_t[index][1] : ""; }
2 Singleton模式的思考
与JavaMe 编程连载(7) - 数据永久存储代码相比,有一处很细微的重构,但不得不提。
private RecordStore record; private String dataBaseName;
重构前的代码为:
private static RecordStore record; private static String dataBaseName;
代码去掉了static关键字。在通用版本中,不能添加该关键字。原因是添加static关键字后,实例存储在一个固定的区域,同一工程中只存在一个实例。在工程中,如果使用多个记录,由于只能存在一个实例,会无法区分记录,造成混乱。Singleton模式请参考设计模式之二 --- Singleton 模式。
*在Eclipse中可利用ctrl+shift+F进行自动排版
转载请标明出处,仅供学习交流,勿用于商业目的
Copyright @ http://blog.csdn.net/tandesir