我正在尝试使用 RecordFilter 过滤一些记录界面。在我的应用程序中,我有几个与此类似的界面,用户可以在其中输入 ID 或名称(他/她可以同时输入或都不输入)
这是我到目前为止所做的事情:
客户过滤器。
这里,如果用户没有输入 ID,我会传递 0 作为默认值,这就是我评估 customerID!=0
的原因
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
private int mID_Filter;
public CustomerFilter(String name_Filter, int id_Filter) {
this.mName_Filter = name_Filter.toLowerCase();
this.mID_Filter = id_Filter;
}
public boolean matches(byte[] candidate) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
int customerID = dis.readInt();
String customerName = dis.readUTF().toLowerCase();
if ((customerName != null && customerName.indexOf(mName_Filter) != -1) && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName != null && customerName.indexOf(mName_Filter) != -1 && customerID == 0)
return true;
if (customerName == null && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName == null && customerID == 0)
return true;
} catch (IOException ex) {
//What's the point in catching a exception here???
}
return false;
}
}
搜索方法:
注意:此方法位于我称为“RMSCustomer”的类中,我在其中处理与 RMS 访问相关的所有内容。 search 方法接收两个参数(id 和 name)并使用它们来实例化过滤器。
public Customer[] search(int id, String name) throws RecordStoreException, IOException {
RecordStore rs = null;
RecordEnumeration recEnum = null;
Customer[] customerList = null;
try {
rs = RecordStore.openRecordStore(mRecordStoreName, true);
if (rs.getNumRecords() > 0) {
CustomerFilter filter = new CustomerFilter(name, id);
try {
recEnum = rs.enumerateRecords(filter, null, false);
if (recEnum.numRecords() > 0) {
customerList = new Customer[recEnum.numRecords()];
int counter = 0;
while (recEnum.hasNextElement()) {
Customer cust;
int idRecord = recEnum.nextRecordId();
byte[] filterRecord = rs.getRecord(idRecord);
cust = parseRecord(filterRecord);
cust.idRecord = idRecord;
customerList[counter] = cust;
counter++;
}
}
else{
customerList = new Customer[0];
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please select another filter"
}
} finally {
recEnum.destroy();
}
}
else{
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please Add record"
}
} finally {
rs.closeRecordStore();
}
return customerList;
}
尽管如此,上面显示的代码可以工作,但我仍然有一些疑问/问题:
在过滤器中:
1) 如何改进评估过滤器可能值(名称、id)的代码?如果我有更多过滤器怎么办?我必须测试所有可能的组合吗?
2)如果用户既没有输入ID也没有输入姓名,我应该显示所有记录还是应该显示一条消息“请输入姓名或ID”?在这种情况下你会怎么做?
3)当我不能在过滤器中做任何事情时,为什么我必须在过滤器中放置一个try-catch?我无法从那里显示任何警报,或者可以吗?
在搜索方法中:
1)如何通过该方法向用户显示正确的消息?类似于“无记录”(请参阅我的代码中的“ELSE”部分
抱歉,如果我问了太多问题,那只是因为有过滤器的完整示例。
提前致谢
请您参考如下方法:
How can I improve the code that evaluates the possible values of the filters (name,id)?
ID 是记录中的第一个字段,也是搜索速度最快的字段。如果 ID 匹配,那么客户名称是什么并不重要。通常,您将查找 ID 匹配或客户名称匹配的记录,因此一旦 ID 匹配,您就可以返回 true。这是我对 CustomerFilter
的建议类:
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
//Use Integer instead of int.
//This way we can use null instead of zero if the user didn't type an ID.
//This allows us to store IDs with values like 0, -1, etc.
//It is a bit less memory efficient,
//but you are not creating hundreds of filters, are you? (If you are, don't).
private Integer mID_Filter;
public CustomerFilter(String name_Filter, Integer id_Filter) {
this.mName_Filter = normalizeString(mName_Filter);
this.mID_Filter = id_Filter;
}
//You should move this function to an StringUtils class and make it public.
//Other filters might need it in the future.
private static String normalizeString(final String s){
if(s != null){
//Warning: you might want to replace accentuated chars as well.
return s.toLowerCase();
}
return null;
}
public boolean matches(byte[] candidate) {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
try {
if(mID_Filter != null){
//If the ID is unique, and the search is ID OR other fields, this is fine
int customerID = dis.readInt();
if(mID_Filter.intValue == customerID){
return true;
} else {
return false;
}
}
if(mName_Filter != null){
String customerName = normalizeString(dis.readUTF());
if(customerName != null && customerName.indexOf(mName_Filter) != -1){
return true;
}
}
if(mID_Filter == null && mName_Filter == null){
return true; // No filtering, every record matches.
}
} catch (IOException ex) {
//Never swallow exceptions.
//Even if you are using an underlying ByteArrayInputStream, an exception
//can still be thrown when reading from DataInputStream if you try to read
//fields that do not exists.
//But even if no exceptions were ever thrown, never swallow exceptions :)
System.err.println(ex);
//Optional: throw ex;
} finally {
//Always close streams.
if(bis != null){
try {
bis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
if(dis != null){
try {
dis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
}
return false;
}
}
What if I had more filters?? Will I have to test all the possible combinations??
这取决于您的项目。通常 ID 是唯一的,不存在具有相同 ID 的两条记录。在这种情况下,您应该明确设计屏幕,以便用户了解他要么键入 ID,要么填写其他字段。条件是这样的:
idMatches OR (field1Matches AND field2Matches AND ... fieldNMatches)
如果用户未输入任何内容,则将返回所有记录。
但话又说回来,这更多的是一个用户体验问题,我不知道它是否适合您的要求。
从编程的角度来看,很明显,添加的字段越多,过滤器就会变得越困惑。为了防止这种情况,您可以使用类似 Decorator 的模式, Composite ,甚至 Chain of responsibility 。不过,您可能必须用良好的设计来换取性能。
If the user doesn’t enter neither a ID nor a name, should I display all the records or should I display a message "Please enter a name or ID"?? What would you do in this case?
这要看情况。还有其他方法可以查看所有记录吗?如果是这样,则显示该消息。
Why do I have to put a try-catch in the filter when I can't do anything there?? I can't show any alert from there or can I?
你不应该。该类只负责过滤,不负责与用户交互。您仍然可以记录 catch 子句中的错误,然后再次引发异常。这会将异常传播到 RMSCustomer.search
,因此无论客户端代码调用该函数,都将以与处理该方法引发的其他异常相同的方式处理异常。但保留finally 子句来关闭流。
How can I show a proper message to the user from that method? something like "No records" (see the "ELSE" parts in my code)
您不应该在 RMSCustomer 类中执行任何与 GUI 相关的操作(例如显示对话框)。即使您没有使用模型- View - Controller 模式,您仍然希望让您的类专注于单一职责(管理记录)。这称为Single responsibility principle 。 将您的类与 GUI 隔离将使您能够在没有 GUI 的环境中测试并重用它。 当结果为零时,无记录情况应由屏幕处理。 lenght == 0 的数组在这里就可以了,屏幕会显示“No results”消息。对于其他类型的错误,您可以扩展 Exception 类并抛出您自己的自定义异常,即:RecordParsingException
,来自RMSCustomer.search
方法。然后,屏幕类会将不同的异常映射到用户语言的错误消息。