【更新】
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.youkuaiyun.com/tandesir